diff --git a/core/authentication/resources/classes/authentication.php b/core/authentication/resources/classes/authentication.php index 583107c24e..2feab2a1e0 100644 --- a/core/authentication/resources/classes/authentication.php +++ b/core/authentication/resources/classes/authentication.php @@ -27,8 +27,6 @@ /** * authentication * - * @method validate uses authentication plugins to check if a user is authorized to login - * @method get_domain used to get the domain name from the URL or username and then sets both domain_name and domain_uuid */ class authentication { @@ -71,168 +69,172 @@ class authentication { /** * validate uses authentication plugins to check if a user is authorized to login + * * @return array|false [plugin] => last plugin used to authenticate the user [authorized] => true or false */ public function validate() { //set default return array as null - $result = null; + $result = null; //use a login message when a login attempt fails - $failed_login_message = null; + $failed_login_message = null; //get the domain_name and domain_uuid - if (!isset($this->domain_name) || !isset($this->domain_uuid)) { - $this->get_domain(); - } + if (!isset($this->domain_name) || !isset($this->domain_uuid)) { + $this->get_domain(); + } //create a settings object to pass to plugins - $this->settings = new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid]); + $this->settings = new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid]); //set the default authentication method to the database - if (empty($_SESSION['authentication']['methods']) || !is_array($_SESSION['authentication']['methods'])) { - $_SESSION['authentication']['methods'][] = 'database'; - } + if (empty($_SESSION['authentication']['methods']) || !is_array($_SESSION['authentication']['methods'])) { + $_SESSION['authentication']['methods'][] = 'database'; + } //set the database as the default plugin - if (!isset($_SESSION['authentication']['methods'])) { - $_SESSION['authentication']['methods'][] = 'database'; - } + if (!isset($_SESSION['authentication']['methods'])) { + $_SESSION['authentication']['methods'][] = 'database'; + } //check if contacts app exists - $contacts_exists = file_exists(dirname(__DIR__, 4) . '/core/contacts/'); + $contacts_exists = file_exists(dirname(__DIR__, 4) . '/core/contacts/'); //use the authentication plugins - foreach ($_SESSION['authentication']['methods'] as $name) { - //already processed the plugin move to the next plugin - if (!empty($_SESSION['authentication']['plugin'][$name]['authorized']) && $_SESSION['authentication']['plugin'][$name]['authorized']) { - continue; + foreach ($_SESSION['authentication']['methods'] as $name) { + //already processed the plugin move to the next plugin + if (!empty($_SESSION['authentication']['plugin'][$name]['authorized']) && $_SESSION['authentication']['plugin'][$name]['authorized']) { + continue; + } + + //prepare variables + $class_name = "plugin_" . $name; + $base = __DIR__ . "/plugins"; + $plugin = $base . "/" . $name . ".php"; + + //process the plugin + if (file_exists($plugin)) { + //run the plugin + $object = new $class_name(); + $object->domain_name = $this->domain_name; + $object->domain_uuid = $this->domain_uuid; + if ($name == 'database' && isset($this->key)) { + $object->key = $this->key; + } + if ($name == 'database' && isset($this->username)) { + $object->username = $this->username; + $object->password = $this->password; + } + //initialize the plugin send the authentication object and settings + $array = $object->$name($this, $this->settings); + + //build a result array + if (!empty($array) && is_array($array)) { + $result['plugin'] = $array["plugin"]; + $result['domain_name'] = $array["domain_name"]; + $result['username'] = $array["username"]; + $result['user_uuid'] = $array["user_uuid"]; + $result['contact_uuid'] = $array["contact_uuid"]; + if ($contacts_exists) { + $result["contact_organization"] = $array["contact_organization"] ?? ''; + $result["contact_name_given"] = $array["contact_name_given"] ?? ''; + $result["contact_name_family"] = $array["contact_name_family"] ?? ''; + $result["contact_image"] = $array["contact_image"] ?? ''; + } + $result['domain_uuid'] = $array["domain_uuid"]; + $result['authorized'] = $array["authorized"]; + + //set the domain_uuid + $this->domain_uuid = $array["domain_uuid"]; + + //set the user_uuid + $this->user_uuid = $array["user_uuid"]; + + //save the result to the authentication plugin + $_SESSION['authentication']['plugin'][$name] = $result; } - //prepare variables - $class_name = "plugin_".$name; - $base = __DIR__ . "/plugins"; - $plugin = $base."/".$name.".php"; - - //process the plugin - if (file_exists($plugin)) { - //run the plugin - $object = new $class_name(); - $object->domain_name = $this->domain_name; - $object->domain_uuid = $this->domain_uuid; - if ($name == 'database' && isset($this->key)) { - $object->key = $this->key; - } - if ($name == 'database' && isset($this->username)) { - $object->username = $this->username; - $object->password = $this->password; - } - //initialize the plugin send the authentication object and settings - $array = $object->$name($this, $this->settings); - - //build a result array - if (!empty($array) && is_array($array)) { - $result['plugin'] = $array["plugin"]; - $result['domain_name'] = $array["domain_name"]; - $result['username'] = $array["username"]; - $result['user_uuid'] = $array["user_uuid"]; - $result['contact_uuid'] = $array["contact_uuid"]; - if ($contacts_exists) { - $result["contact_organization"] = $array["contact_organization"] ?? ''; - $result["contact_name_given"] = $array["contact_name_given"] ?? ''; - $result["contact_name_family"] = $array["contact_name_family"] ?? ''; - $result["contact_image"] = $array["contact_image"] ?? ''; - } - $result['domain_uuid'] = $array["domain_uuid"]; - $result['authorized'] = $array["authorized"]; - - //set the domain_uuid - $this->domain_uuid = $array["domain_uuid"]; - - //set the user_uuid - $this->user_uuid = $array["user_uuid"]; - - //save the result to the authentication plugin - $_SESSION['authentication']['plugin'][$name] = $result; - } - - //plugin authorized false - if (!$result['authorized']) { - break; - } + //plugin authorized false + if (!$result['authorized']) { + break; } } + } //make sure all plugins are in the array - if (!empty($_SESSION['authentication']['methods'])) { - foreach ($_SESSION['authentication']['methods'] as $name) { - if (!isset($_SESSION['authentication']['plugin'][$name]['authorized'])) { - $_SESSION['authentication']['plugin'][$name]['plugin'] = $name; - $_SESSION['authentication']['plugin'][$name]['domain_name'] = $_SESSION['domain_name']; - $_SESSION['authentication']['plugin'][$name]['domain_uuid'] = $_SESSION['domain_uuid']; - $_SESSION['authentication']['plugin'][$name]['username'] = $_SESSION['username']; - $_SESSION['authentication']['plugin'][$name]['user_uuid'] = $_SESSION['user_uuid']; - $_SESSION['authentication']['plugin'][$name]['user_email'] = $_SESSION['user_email']; - $_SESSION['authentication']['plugin'][$name]['authorized'] = false; - } + if (!empty($_SESSION['authentication']['methods'])) { + foreach ($_SESSION['authentication']['methods'] as $name) { + if (!isset($_SESSION['authentication']['plugin'][$name]['authorized'])) { + $_SESSION['authentication']['plugin'][$name]['plugin'] = $name; + $_SESSION['authentication']['plugin'][$name]['domain_name'] = $_SESSION['domain_name']; + $_SESSION['authentication']['plugin'][$name]['domain_uuid'] = $_SESSION['domain_uuid']; + $_SESSION['authentication']['plugin'][$name]['username'] = $_SESSION['username']; + $_SESSION['authentication']['plugin'][$name]['user_uuid'] = $_SESSION['user_uuid']; + $_SESSION['authentication']['plugin'][$name]['user_email'] = $_SESSION['user_email']; + $_SESSION['authentication']['plugin'][$name]['authorized'] = false; } } + } //debug information - //view_array($_SESSION['authentication'], false); + //view_array($_SESSION['authentication'], false); //set authorized to false if any authentication method failed - $authorized = false; - $plugin_name = ''; - if (is_array($_SESSION['authentication']['plugin'])) { - foreach($_SESSION['authentication']['plugin'] as $row) { - $plugin_name = $row['plugin']; - if ($row["authorized"]) { - $authorized = true; - } - else { - $authorized = false; - $failed_login_message = "Authentication plugin '$plugin_name' blocked login attempt"; - break; - } + $authorized = false; + $plugin_name = ''; + if (is_array($_SESSION['authentication']['plugin'])) { + foreach ($_SESSION['authentication']['plugin'] as $row) { + $plugin_name = $row['plugin']; + if ($row["authorized"]) { + $authorized = true; + } else { + $authorized = false; + $failed_login_message = "Authentication plugin '$plugin_name' blocked login attempt"; + break; } } + } //user is authorized - get user settings, check user cidr - if ($authorized) { - //get the cidr restrictions from global, domain, and user default settings - $this->settings = new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - $cidr_list = $this->settings->get('domain', 'cidr', []); - if (check_cidr($cidr_list, $_SERVER['REMOTE_ADDR'])) { - //user passed the cidr check - self::create_user_session($result, $this->settings); - } else { - //user failed the cidr check - no longer authorized - $authorized = false; - $failed_login_message = "CIDR blocked login attempt"; - $_SESSION['authentication']['plugin'][$name]['authorized'] = false; - } + if ($authorized) { + //get the cidr restrictions from global, domain, and user default settings + $this->settings = new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + $cidr_list = $this->settings->get('domain', 'cidr', []); + if (check_cidr($cidr_list, $_SERVER['REMOTE_ADDR'])) { + //user passed the cidr check + self::create_user_session($result, $this->settings); + } else { + //user failed the cidr check - no longer authorized + $authorized = false; + $failed_login_message = "CIDR blocked login attempt"; + $_SESSION['authentication']['plugin'][$name]['authorized'] = false; } + } //set a session variable to indicate whether or not we are authorized - $_SESSION['authorized'] = $authorized; + $_SESSION['authorized'] = $authorized; //log the attempt - user_logs::add($_SESSION['authentication']['plugin'][$name], $failed_login_message); + user_logs::add($_SESSION['authentication']['plugin'][$name], $failed_login_message); //return the result - return $result ?? false; + return $result ?? false; } /** * Creates a valid user session in the superglobal $_SESSION. *

The $result must be a validated user with the appropriate variables set.
* The associative array - * @global database $database - * @global string $conf - * @param array|bool $result Associative array containing: domain_uuid, domain_name, user_uuid, username. Contact keys can be empty, but should still be present. They include: contact_uuid, contact_name_given, contact_name_family, contact_image. - * @param settings $settings From the settings object + * + * @param array|bool $result Associative array containing: domain_uuid, domain_name, user_uuid, username. Contact + * keys can be empty, but should still be present. They include: contact_uuid, + * contact_name_given, contact_name_family, contact_image. + * @param settings $settings From the settings object + * * @return void + * @global string $conf + * @global database $database */ public static function create_user_session($result = [], $settings = null): void { @@ -248,8 +250,8 @@ class authentication { $required_keys = [ 'domain_uuid' => true, 'domain_name' => true, - 'user_uuid' => true, - 'username' => true, + 'user_uuid' => true, + 'username' => true, ]; // Any missing required_fields are left in the $diff array. @@ -281,8 +283,8 @@ class authentication { // Set the session variables $_SESSION["domain_uuid"] = $result["domain_uuid"]; $_SESSION["domain_name"] = $result["domain_name"]; - $_SESSION["user_uuid"] = $result["user_uuid"]; - $_SESSION["context"] = $result['domain_name']; + $_SESSION["user_uuid"] = $result["user_uuid"]; + $_SESSION["context"] = $result['domain_name']; // Build the session server array to validate the session global $conf; @@ -297,19 +299,19 @@ class authentication { $_SESSION["user_hash"] = hash('sha256', implode($server_array)); // User session array - $_SESSION["user"]["domain_uuid"] = $result["domain_uuid"]; - $_SESSION["user"]["domain_name"] = $result["domain_name"]; - $_SESSION["user"]["user_uuid"] = $result["user_uuid"]; - $_SESSION["user"]["username"] = $result["username"]; + $_SESSION["user"]["domain_uuid"] = $result["domain_uuid"]; + $_SESSION["user"]["domain_name"] = $result["domain_name"]; + $_SESSION["user"]["user_uuid"] = $result["user_uuid"]; + $_SESSION["user"]["username"] = $result["username"]; $_SESSION["user"]["contact_uuid"] = $result["contact_uuid"] ?? null; //contact_uuid is optional // Check for contacts if (file_exists($project_root . '/core/contacts/')) { $_SESSION["user"]["contact_organization"] = $result["contact_organization"] ?? null; - $_SESSION["user"]["contact_name"] = trim(($result["contact_name_given"] ?? '') . ' ' . ($result["contact_name_family"] ?? '')); - $_SESSION["user"]["contact_name_given"] = $result["contact_name_given"] ?? null; - $_SESSION["user"]["contact_name_family"] = $result["contact_name_family"] ?? null; - $_SESSION["user"]["contact_image"] = !empty($result["contact_image"]) && is_uuid($result["contact_image"]) ? $result["contact_image"] : null; + $_SESSION["user"]["contact_name"] = trim(($result["contact_name_given"] ?? '') . ' ' . ($result["contact_name_family"] ?? '')); + $_SESSION["user"]["contact_name_given"] = $result["contact_name_given"] ?? null; + $_SESSION["user"]["contact_name_family"] = $result["contact_name_family"] ?? null; + $_SESSION["user"]["contact_image"] = !empty($result["contact_image"]) && is_uuid($result["contact_image"]) ? $result["contact_image"] : null; } //empty the permissions @@ -334,19 +336,19 @@ class authentication { $parameters = []; //get the user settings - $sql = "select * from v_user_settings "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and user_uuid = :user_uuid "; - $sql .= "and user_setting_enabled = true "; + $sql = "select * from v_user_settings "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and user_uuid = :user_uuid "; + $sql .= "and user_setting_enabled = true "; $parameters['domain_uuid'] = $result["domain_uuid"]; - $parameters['user_uuid'] = $result["user_uuid"]; - $user_settings = $database->select($sql, $parameters, 'all'); + $parameters['user_uuid'] = $result["user_uuid"]; + $user_settings = $database->select($sql, $parameters, 'all'); //store user settings in the session when available if (is_array($user_settings)) { foreach ($user_settings as $row) { - $name = $row['user_setting_name']; - $category = $row['user_setting_category']; + $name = $row['user_setting_name']; + $category = $row['user_setting_category']; $subcategory = $row['user_setting_subcategory']; if (isset($row['user_setting_value'])) { if (empty($subcategory)) { @@ -378,27 +380,27 @@ class authentication { $_SESSION['user']['extension'] = []; //get the user extension list - $sql = "select "; - $sql .= "e.extension_uuid, "; - $sql .= "e.extension, "; - $sql .= "e.number_alias, "; - $sql .= "e.user_context, "; - $sql .= "e.outbound_caller_id_name, "; - $sql .= "e.outbound_caller_id_number, "; - $sql .= "e.description "; - $sql .= "from "; - $sql .= "v_extension_users as u, "; - $sql .= "v_extensions as e "; - $sql .= "where "; - $sql .= "e.domain_uuid = :domain_uuid "; - $sql .= "and e.extension_uuid = u.extension_uuid "; - $sql .= "and u.user_uuid = :user_uuid "; - $sql .= "and e.enabled = 'true' "; - $sql .= "order by "; - $sql .= "e.extension asc "; + $sql = "select "; + $sql .= "e.extension_uuid, "; + $sql .= "e.extension, "; + $sql .= "e.number_alias, "; + $sql .= "e.user_context, "; + $sql .= "e.outbound_caller_id_name, "; + $sql .= "e.outbound_caller_id_number, "; + $sql .= "e.description "; + $sql .= "from "; + $sql .= "v_extension_users as u, "; + $sql .= "v_extensions as e "; + $sql .= "where "; + $sql .= "e.domain_uuid = :domain_uuid "; + $sql .= "and e.extension_uuid = u.extension_uuid "; + $sql .= "and u.user_uuid = :user_uuid "; + $sql .= "and e.enabled = 'true' "; + $sql .= "order by "; + $sql .= "e.extension asc "; $parameters['domain_uuid'] = $_SESSION['domain_uuid']; - $parameters['user_uuid'] = $_SESSION['user_uuid']; - $extensions = $database->select($sql, $parameters, 'all'); + $parameters['user_uuid'] = $_SESSION['user_uuid']; + $extensions = $database->select($sql, $parameters, 'all'); if (!empty($extensions)) { foreach ($extensions as $x => $row) { //set the destination @@ -408,18 +410,18 @@ class authentication { } //build the user array - $_SESSION['user']['extension'][$x]['user'] = $row['extension']; - $_SESSION['user']['extension'][$x]['number_alias'] = $row['number_alias']; - $_SESSION['user']['extension'][$x]['destination'] = $destination; - $_SESSION['user']['extension'][$x]['extension_uuid'] = $row['extension_uuid']; - $_SESSION['user']['extension'][$x]['outbound_caller_id_name'] = $row['outbound_caller_id_name']; + $_SESSION['user']['extension'][$x]['user'] = $row['extension']; + $_SESSION['user']['extension'][$x]['number_alias'] = $row['number_alias']; + $_SESSION['user']['extension'][$x]['destination'] = $destination; + $_SESSION['user']['extension'][$x]['extension_uuid'] = $row['extension_uuid']; + $_SESSION['user']['extension'][$x]['outbound_caller_id_name'] = $row['outbound_caller_id_name']; $_SESSION['user']['extension'][$x]['outbound_caller_id_number'] = $row['outbound_caller_id_number']; - $_SESSION['user']['extension'][$x]['user_context'] = $row['user_context']; - $_SESSION['user']['extension'][$x]['description'] = $row['description']; + $_SESSION['user']['extension'][$x]['user_context'] = $row['user_context']; + $_SESSION['user']['extension'][$x]['description'] = $row['description']; //set the context $_SESSION['user']['user_context'] = $row["user_context"]; - $_SESSION['user_context'] = $row["user_context"]; + $_SESSION['user_context'] = $row["user_context"]; } } } @@ -451,81 +453,81 @@ class authentication { public function get_domain() { //get the domain from the url - $this->domain_name = $_SERVER["HTTP_HOST"]; + $this->domain_name = $_SERVER["HTTP_HOST"]; //get the domain name from the http value - if (!empty($_REQUEST["domain_name"])) { - $this->domain_name = $_REQUEST["domain_name"]; - } + if (!empty($_REQUEST["domain_name"])) { + $this->domain_name = $_REQUEST["domain_name"]; + } //remote port number from the domain name - $domain_array = explode(":", $this->domain_name); - if (count($domain_array) > 1) { - $domain_name = $domain_array[0]; - } + $domain_array = explode(":", $this->domain_name); + if (count($domain_array) > 1) { + $domain_name = $domain_array[0]; + } //if the username - if (!empty($_REQUEST["username"])) { - $_SESSION['username'] = $_REQUEST["username"]; - } + if (!empty($_REQUEST["username"])) { + $_SESSION['username'] = $_REQUEST["username"]; + } //set a default value for unqiue - $_SESSION["users"]["unique"]["text"] = $this->settings->get('users', 'unique', ''); + $_SESSION["users"]["unique"]["text"] = $this->settings->get('users', 'unique', ''); //get the domain name from the username - if (!empty($_SESSION['username']) && $this->settings->get('users', 'unique', '') != "global") { - $username_array = explode("@", $_SESSION['username']); - if (count($username_array) > 1) { - //get the domain name - $domain_name = $username_array[count($username_array) -1]; + if (!empty($_SESSION['username']) && $this->settings->get('users', 'unique', '') != "global") { + $username_array = explode("@", $_SESSION['username']); + if (count($username_array) > 1) { + //get the domain name + $domain_name = $username_array[count($username_array) - 1]; - //check if the domain from the username exists - $domain_exists = false; - foreach ($_SESSION['domains'] as $row) { - if (lower_case($row['domain_name']) == lower_case($domain_name)) { - $this->domain_uuid = $row['domain_uuid']; - $domain_exists = true; - break; - } - } - - //if the domain exists then set domain_name and update the username - if ($domain_exists) { - $this->domain_name = $domain_name; - $this->username = substr($_SESSION['username'], 0, -(strlen($domain_name)+1)); - //$_SESSION['domain_name'] = $domain_name; - $_SESSION['username'] = $this->username; - $_SESSION['domain_uuid'] = $this->domain_uuid; - } - - //unset the domain name variable - unset($domain_name); - } - } - - //get the domain uuid and domain settings - if (isset($this->domain_name) && !isset($this->domain_uuid)) { + //check if the domain from the username exists + $domain_exists = false; foreach ($_SESSION['domains'] as $row) { - if (lower_case($row['domain_name']) == lower_case($this->domain_name)) { + if (lower_case($row['domain_name']) == lower_case($domain_name)) { $this->domain_uuid = $row['domain_uuid']; - $_SESSION['domain_uuid'] = $row['domain_uuid']; + $domain_exists = true; break; } } + + //if the domain exists then set domain_name and update the username + if ($domain_exists) { + $this->domain_name = $domain_name; + $this->username = substr($_SESSION['username'], 0, -(strlen($domain_name) + 1)); + //$_SESSION['domain_name'] = $domain_name; + $_SESSION['username'] = $this->username; + $_SESSION['domain_uuid'] = $this->domain_uuid; + } + + //unset the domain name variable + unset($domain_name); } + } + + //get the domain uuid and domain settings + if (isset($this->domain_name) && !isset($this->domain_uuid)) { + foreach ($_SESSION['domains'] as $row) { + if (lower_case($row['domain_name']) == lower_case($this->domain_name)) { + $this->domain_uuid = $row['domain_uuid']; + $_SESSION['domain_uuid'] = $row['domain_uuid']; + break; + } + } + } //set the setting arrays - $obj = new domains(['database' => $this->database]); - $obj->set(); + $obj = new domains(['database' => $this->database]); + $obj->set(); //set the domain settings - if (!empty($this->domain_name) && !empty($_SESSION["domain_uuid"])) { - $_SESSION['domain_name'] = $this->domain_name; - $_SESSION['domain_parent_uuid'] = $_SESSION["domain_uuid"]; - } + if (!empty($this->domain_name) && !empty($_SESSION["domain_uuid"])) { + $_SESSION['domain_name'] = $this->domain_name; + $_SESSION['domain_parent_uuid'] = $_SESSION["domain_uuid"]; + } //set the domain name - return $this->domain_name; + return $this->domain_name; } } diff --git a/core/authentication/resources/classes/plugins/database.php b/core/authentication/resources/classes/plugins/database.php index baf3177212..e52107bf0c 100644 --- a/core/authentication/resources/classes/plugins/database.php +++ b/core/authentication/resources/classes/plugins/database.php @@ -50,351 +50,347 @@ class plugin_database { /** * database checks the local database to authenticate the user or key + * * @return array [authorized] => true or false */ function database(authentication $auth, settings $settings) { //pre-process some settings - $theme_favicon = $settings->get('theme', 'favicon', PROJECT_PATH.'/themes/default/favicon.ico'); - $theme_logo = $settings->get('theme', 'logo', PROJECT_PATH.'/themes/default/images/logo_login.png'); - $theme_login_type = $settings->get('theme', 'login_brand_type', ''); - $theme_login_image = $settings->get('theme', 'login_brand_image', ''); - $theme_login_text = $settings->get('theme', 'login_brand_text', ''); - $theme_login_logo_width = $settings->get('theme', 'login_logo_width', 'auto; max-width: 300px'); - $theme_login_logo_height = $settings->get('theme', 'login_logo_height', 'auto; max-height: 300px'); - $theme_message_delay = 1000 * (float)$settings->get('theme', 'message_delay', 3000); - $background_videos = $settings->get('theme', 'background_video', []); - $theme_background_video = (isset($background_videos[0])) ? $background_videos[0] : ''; - $login_domain_name_visible = $settings->get('login', 'domain_name_visible', false); - $login_domain_name = $settings->get('login', 'domain_name'); - $login_destination = $settings->get('login', 'destination'); - $users_unique = $settings->get('users', 'unique', ''); + $theme_favicon = $settings->get('theme', 'favicon', PROJECT_PATH . '/themes/default/favicon.ico'); + $theme_logo = $settings->get('theme', 'logo', PROJECT_PATH . '/themes/default/images/logo_login.png'); + $theme_login_type = $settings->get('theme', 'login_brand_type', ''); + $theme_login_image = $settings->get('theme', 'login_brand_image', ''); + $theme_login_text = $settings->get('theme', 'login_brand_text', ''); + $theme_login_logo_width = $settings->get('theme', 'login_logo_width', 'auto; max-width: 300px'); + $theme_login_logo_height = $settings->get('theme', 'login_logo_height', 'auto; max-height: 300px'); + $theme_message_delay = 1000 * (float)$settings->get('theme', 'message_delay', 3000); + $background_videos = $settings->get('theme', 'background_video', []); + $theme_background_video = (isset($background_videos[0])) ? $background_videos[0] : ''; + $login_domain_name_visible = $settings->get('login', 'domain_name_visible', false); + $login_domain_name = $settings->get('login', 'domain_name'); + $login_destination = $settings->get('login', 'destination'); + $users_unique = $settings->get('users', 'unique', ''); //set the default login type and image - if (empty($theme_login_type)) { - $theme_login_type = 'image'; - $theme_login_image = $theme_logo; - } + if (empty($theme_login_type)) { + $theme_login_type = 'image'; + $theme_login_image = $theme_logo; + } //determine whether to show the forgot password for resetting the password - $login_password_reset_enabled = false; - if (!empty($settings->get('login', 'password_reset_key'))) { - $login_password_reset_enabled = true; - } + $login_password_reset_enabled = false; + if (!empty($settings->get('login', 'password_reset_key'))) { + $login_password_reset_enabled = true; + } //check if already authorized - if (isset($_SESSION['authentication']['plugin']['database']) && $_SESSION['authentication']['plugin']['database']["authorized"]) { - return; - } + if (isset($_SESSION['authentication']['plugin']['database']) && $_SESSION['authentication']['plugin']['database']["authorized"]) { + return; + } //show the authentication code view - if (empty($_REQUEST["username"]) && empty($_REQUEST["key"])) { + if (empty($_REQUEST["username"]) && empty($_REQUEST["key"])) { - //get the domain - $domain_array = explode(":", $_SERVER["HTTP_HOST"]); - $domain_name = $domain_array[0]; + //get the domain + $domain_array = explode(":", $_SERVER["HTTP_HOST"]); + $domain_name = $domain_array[0]; - //create token - //$object = new token; - //$token = $object->create('login'); + //create token + //$object = new token; + //$token = $object->create('login'); - //add multi-lingual support - $language = new text; - $text = $language->get(null, '/core/authentication'); + //add multi-lingual support + $language = new text; + $text = $language->get(null, '/core/authentication'); - //initialize a template object - $view = new template(); - $view->engine = 'smarty'; - $view->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/authentication/resources/views/'; - $view->cache_dir = sys_get_temp_dir(); - $view->init(); + //initialize a template object + $view = new template(); + $view->engine = 'smarty'; + $view->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/authentication/resources/views/'; + $view->cache_dir = sys_get_temp_dir(); + $view->init(); - //add translations - $view->assign("login_title", $text['button-login']); - $view->assign("label_username", $text['label-username']); - $view->assign("label_password", $text['label-password']); - $view->assign("label_domain", $text['label-domain']); - $view->assign("button_login", $text['button-login']); + //add translations + $view->assign("login_title", $text['button-login']); + $view->assign("label_username", $text['label-username']); + $view->assign("label_password", $text['label-password']); + $view->assign("label_domain", $text['label-domain']); + $view->assign("button_login", $text['button-login']); - //assign default values to the template - $view->assign("project_path", PROJECT_PATH); - $view->assign("login_destination_url", $login_destination); - $view->assign("login_domain_name_visible", $login_domain_name_visible); - $view->assign("login_domain_names", $login_domain_name); - $view->assign("login_password_reset_enabled", $login_password_reset_enabled); - $view->assign("favicon", $theme_favicon); - $view->assign("login_logo_width", $theme_login_logo_width); - $view->assign("login_logo_height", $theme_login_logo_height); - $view->assign("login_logo_source", $theme_logo); - $view->assign("message_delay", $theme_message_delay); - $view->assign("background_video", $theme_background_video); - $view->assign("login_password_description", $text['label-password_description']); - $view->assign("button_cancel", $text['button-cancel']); - $view->assign("button_forgot_password", $text['button-forgot_password']); + //assign default values to the template + $view->assign("project_path", PROJECT_PATH); + $view->assign("login_destination_url", $login_destination); + $view->assign("login_domain_name_visible", $login_domain_name_visible); + $view->assign("login_domain_names", $login_domain_name); + $view->assign("login_password_reset_enabled", $login_password_reset_enabled); + $view->assign("favicon", $theme_favicon); + $view->assign("login_logo_width", $theme_login_logo_width); + $view->assign("login_logo_height", $theme_login_logo_height); + $view->assign("login_logo_source", $theme_logo); + $view->assign("message_delay", $theme_message_delay); + $view->assign("background_video", $theme_background_video); + $view->assign("login_password_description", $text['label-password_description']); + $view->assign("button_cancel", $text['button-cancel']); + $view->assign("button_forgot_password", $text['button-forgot_password']); - //assign openid values to the template - if ($settings->get('open_id', 'enabled', false)) { - $classes = $settings->get('open_id', 'methods', []); - $banners = []; - foreach ($classes as $open_id_class) { - if (class_exists($open_id_class)) { - $banners[] = [ - 'name' => $open_id_class, - 'image' => $open_id_class::get_banner_image($settings), - 'class' => $open_id_class::get_banner_css_class($settings), - 'url' => '/app/open_id/open_id.php?action=' . $open_id_class, - ]; - } - } - if (count($banners) > 0) { - $view->assign('banners', $banners); - } + //assign openid values to the template + if ($settings->get('open_id', 'enabled', false)) { + $classes = $settings->get('open_id', 'methods', []); + $banners = []; + foreach ($classes as $open_id_class) { + if (class_exists($open_id_class)) { + $banners[] = [ + 'name' => $open_id_class, + 'image' => $open_id_class::get_banner_image($settings), + 'class' => $open_id_class::get_banner_css_class($settings), + 'url' => '/app/open_id/open_id.php?action=' . $open_id_class, + ]; } - - //assign user to the template - if (!empty($_SESSION['username'])) { - $view->assign("username", $_SESSION['username']); - } - - //messages - $view->assign('messages', message::html(true, ' ')); - - //add the token name and hash to the view - //$view->assign("token_name", $token['name']); - //$view->assign("token_hash", $token['hash']); - - //show the views - $content = $view->render('login.htm'); - echo $content; - exit; + } + if (count($banners) > 0) { + $view->assign('banners', $banners); + } } + //assign user to the template + if (!empty($_SESSION['username'])) { + $view->assign("username", $_SESSION['username']); + } + + //messages + $view->assign('messages', message::html(true, ' ')); + + //add the token name and hash to the view + //$view->assign("token_name", $token['name']); + //$view->assign("token_hash", $token['hash']); + + //show the views + $content = $view->render('login.htm'); + echo $content; + exit; + } + //validate the token - //$token = new token; - //if (!$token->validate($_SERVER['PHP_SELF'])) { - // message::add($text['message-invalid_token'],'negative'); - // header('Location: domains.php'); - // exit; - //} + //$token = new token; + //if (!$token->validate($_SERVER['PHP_SELF'])) { + // message::add($text['message-invalid_token'],'negative'); + // header('Location: domains.php'); + // exit; + //} //add the authentication details - if (isset($_REQUEST["username"])) { - $this->username = $_REQUEST["username"]; - $_SESSION['username'] = $this->username; - } - if (isset($_REQUEST["password"])) { - $this->password = $_REQUEST["password"]; - } - if (isset($_REQUEST["key"])) { - $this->key = $_REQUEST["key"]; - } - if (isset($_REQUEST["domain_name"])) { - $domain_name = $_REQUEST["domain_name"]; - $this->domain_name = $_REQUEST["domain_name"]; - } + if (isset($_REQUEST["username"])) { + $this->username = $_REQUEST["username"]; + $_SESSION['username'] = $this->username; + } + if (isset($_REQUEST["password"])) { + $this->password = $_REQUEST["password"]; + } + if (isset($_REQUEST["key"])) { + $this->key = $_REQUEST["key"]; + } + if (isset($_REQUEST["domain_name"])) { + $domain_name = $_REQUEST["domain_name"]; + $this->domain_name = $_REQUEST["domain_name"]; + } //get the domain name - $auth->get_domain(); - $this->username = $_SESSION['username'] ?? null; - //$this->domain_uuid = $_SESSION['domain_uuid'] ?? null; - //$this->domain_name = $_SESSION['domain_name'] ?? null; + $auth->get_domain(); + $this->username = $_SESSION['username'] ?? null; + //$this->domain_uuid = $_SESSION['domain_uuid'] ?? null; + //$this->domain_name = $_SESSION['domain_name'] ?? null; //debug information - //echo "domain_uuid: ".$this->domain_uuid."
\n"; - //view_array($this->domain_uuid, false); - //echo "domain_name: ".$this->domain_name."
\n"; - //echo "username: ".$this->username."
\n"; + //echo "domain_uuid: ".$this->domain_uuid."
\n"; + //view_array($this->domain_uuid, false); + //echo "domain_name: ".$this->domain_name."
\n"; + //echo "username: ".$this->username."
\n"; //set the default status - $user_authorized = false; + $user_authorized = false; //check if contacts app exists - $contacts_exists = file_exists($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/contacts/') ? true : false; + $contacts_exists = file_exists($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/contacts/') ? true : false; //check the username and password if they don't match then redirect to the login - $sql = "select "; - $sql .= " d.domain_name, "; - $sql .= " u.user_uuid, "; - $sql .= " u.contact_uuid, "; - $sql .= " u.username, "; - $sql .= " u.password, "; - $sql .= " u.user_email, "; - $sql .= " u.salt, "; - $sql .= " u.api_key, "; - $sql .= " u.domain_uuid "; - $sql .= "from "; - $sql .= " v_domains as d, "; - $sql .= " v_users as u "; - $sql .= "where "; - $sql .= " u.domain_uuid = d.domain_uuid "; - $sql .= " and ("; - $sql .= " user_type = 'default' "; - $sql .= " or user_type is null"; - $sql .= " ) "; - if (isset($this->key) && strlen($this->key) > 30) { - $sql .= "and u.api_key = :api_key "; - $parameters['api_key'] = $this->key; - } - else { - $sql .= "and (\n"; - $sql .= " lower(u.username) = lower(:username)\n"; - $sql .= " or lower(u.user_email) = lower(:username)\n"; - $sql .= ")\n"; - $parameters['username'] = $this->username; - } - if ($users_unique === "global") { - //unique username - global (example: email address) - } - else { - //unique username - per domain - $sql .= "and u.domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $sql .= "and (user_enabled = true or user_enabled is null) "; - $row = $settings->database()->select($sql, $parameters, 'row'); - if (!empty($row) && is_array($row) && @sizeof($row) != 0) { + $sql = "select "; + $sql .= " d.domain_name, "; + $sql .= " u.user_uuid, "; + $sql .= " u.contact_uuid, "; + $sql .= " u.username, "; + $sql .= " u.password, "; + $sql .= " u.user_email, "; + $sql .= " u.salt, "; + $sql .= " u.api_key, "; + $sql .= " u.domain_uuid "; + $sql .= "from "; + $sql .= " v_domains as d, "; + $sql .= " v_users as u "; + $sql .= "where "; + $sql .= " u.domain_uuid = d.domain_uuid "; + $sql .= " and ("; + $sql .= " user_type = 'default' "; + $sql .= " or user_type is null"; + $sql .= " ) "; + if (isset($this->key) && strlen($this->key) > 30) { + $sql .= "and u.api_key = :api_key "; + $parameters['api_key'] = $this->key; + } else { + $sql .= "and (\n"; + $sql .= " lower(u.username) = lower(:username)\n"; + $sql .= " or lower(u.user_email) = lower(:username)\n"; + $sql .= ")\n"; + $parameters['username'] = $this->username; + } + if ($users_unique === "global") { + //unique username - global (example: email address) + } else { + //unique username - per domain + $sql .= "and u.domain_uuid = :domain_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $sql .= "and (user_enabled = true or user_enabled is null) "; + $row = $settings->database()->select($sql, $parameters, 'row'); + if (!empty($row) && is_array($row) && @sizeof($row) != 0) { - //validate the password - $valid_password = false; - if (isset($this->key) && strlen($this->key) > 30 && $this->key === $row["api_key"]) { + //validate the password + $valid_password = false; + if (isset($this->key) && strlen($this->key) > 30 && $this->key === $row["api_key"]) { + $valid_password = true; + } elseif (substr($row["password"], 0, 1) === '$') { + if (isset($this->password) && !empty($this->password)) { + if (password_verify($this->password, $row["password"])) { $valid_password = true; } - else if (substr($row["password"], 0, 1) === '$') { - if (isset($this->password) && !empty($this->password)) { - if (password_verify($this->password, $row["password"])) { - $valid_password = true; - } - } - } - else { - //deprecated - compare the password provided by the user with the one in the database - if (md5($row["salt"].$this->password) === $row["password"]) { - $row["password"] = crypt($this->password, '$1$'.$row['salt'].'$'); - $valid_password = true; - } - } + } + } else { + //deprecated - compare the password provided by the user with the one in the database + if (md5($row["salt"] . $this->password) === $row["password"]) { + $row["password"] = crypt($this->password, '$1$' . $row['salt'] . '$'); + $valid_password = true; + } + } - //set the domain and user settings - if ($valid_password) { - //set the domain_uuid - $this->domain_uuid = $row["domain_uuid"]; - $this->domain_name = $row["domain_name"]; + //set the domain and user settings + if ($valid_password) { + //set the domain_uuid + $this->domain_uuid = $row["domain_uuid"]; + $this->domain_name = $row["domain_name"]; - //set the domain session variables - $_SESSION["domain_uuid"] = $this->domain_uuid; - $_SESSION["domain_name"] = $this->domain_name; + //set the domain session variables + $_SESSION["domain_uuid"] = $this->domain_uuid; + $_SESSION["domain_name"] = $this->domain_name; - //set the domain setting - if ($users_unique === "global" && $row["domain_uuid"] !== $this->domain_uuid) { - $domain = new domains(); - $domain->set(); - } + //set the domain setting + if ($users_unique === "global" && $row["domain_uuid"] !== $this->domain_uuid) { + $domain = new domains(); + $domain->set(); + } - //set the variables - $this->user_uuid = $row['user_uuid']; - $this->username = $row['username']; - $this->user_email = $row['user_email']; - $this->contact_uuid = $row['contact_uuid']; + //set the variables + $this->user_uuid = $row['user_uuid']; + $this->username = $row['username']; + $this->user_email = $row['user_email']; + $this->contact_uuid = $row['contact_uuid']; - //get the user contact details - if ($contacts_exists) { - unset($parameters); - $sql = "select "; - $sql .= " c.contact_organization, "; - $sql .= " c.contact_name_given, "; - $sql .= " c.contact_name_family, "; - $sql .= " a.contact_attachment_uuid "; - $sql .= "from v_contacts as c "; - $sql .= "left join v_contact_attachments as a on c.contact_uuid = a.contact_uuid "; - $sql .= "where c.contact_uuid = :contact_uuid "; - $sql .= "and c.domain_uuid = :domain_uuid "; - $sql .= "and a.attachment_primary = true "; - $sql .= "and a.attachment_filename is not null "; - $sql .= "and a.attachment_content is not null "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['contact_uuid'] = $this->contact_uuid; - $contact = $settings->database()->select($sql, $parameters, 'row'); - $this->contact_organization = $contact['contact_organization'] ?? ''; - $this->contact_name_given = $contact['contact_name_given'] ?? ''; - $this->contact_name_family = $contact['contact_name_family'] ?? ''; - $this->contact_image = $contact['contact_attachment_uuid'] ?? ''; - } + //get the user contact details + if ($contacts_exists) { + unset($parameters); + $sql = "select "; + $sql .= " c.contact_organization, "; + $sql .= " c.contact_name_given, "; + $sql .= " c.contact_name_family, "; + $sql .= " a.contact_attachment_uuid "; + $sql .= "from v_contacts as c "; + $sql .= "left join v_contact_attachments as a on c.contact_uuid = a.contact_uuid "; + $sql .= "where c.contact_uuid = :contact_uuid "; + $sql .= "and c.domain_uuid = :domain_uuid "; + $sql .= "and a.attachment_primary = true "; + $sql .= "and a.attachment_filename is not null "; + $sql .= "and a.attachment_content is not null "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['contact_uuid'] = $this->contact_uuid; + $contact = $settings->database()->select($sql, $parameters, 'row'); + $this->contact_organization = $contact['contact_organization'] ?? ''; + $this->contact_name_given = $contact['contact_name_given'] ?? ''; + $this->contact_name_family = $contact['contact_name_family'] ?? ''; + $this->contact_image = $contact['contact_attachment_uuid'] ?? ''; + } - //debug info - //echo "user_uuid ".$this->user_uuid."
\n"; - //echo "username ".$this->username."
\n"; - //echo "contact_uuid ".$this->contact_uuid."
\n"; + //debug info + //echo "user_uuid ".$this->user_uuid."
\n"; + //echo "username ".$this->username."
\n"; + //echo "contact_uuid ".$this->contact_uuid."
\n"; - //set a few session variables - $_SESSION["user_uuid"] = $row['user_uuid']; - $_SESSION["username"] = $row['username']; - $_SESSION["user_email"] = $row['user_email']; - $_SESSION["contact_uuid"] = $row["contact_uuid"]; - } + //set a few session variables + $_SESSION["user_uuid"] = $row['user_uuid']; + $_SESSION["username"] = $row['username']; + $_SESSION["user_email"] = $row['user_email']; + $_SESSION["contact_uuid"] = $row["contact_uuid"]; + } - //check to to see if the the password hash needs to be updated - if ($valid_password) { - //set the password hash cost - $options = array('cost' => 10); + //check to to see if the the password hash needs to be updated + if ($valid_password) { + //set the password hash cost + $options = ['cost' => 10]; - //check if a newer hashing algorithm is available or the cost has changed - if (password_needs_rehash($row["password"], PASSWORD_DEFAULT, $options)) { + //check if a newer hashing algorithm is available or the cost has changed + if (password_needs_rehash($row["password"], PASSWORD_DEFAULT, $options)) { - //build user insert array - $array = []; - $array['users'][0]['user_uuid'] = $this->user_uuid; - $array['users'][0]['domain_uuid'] = $this->domain_uuid; - $array['users'][0]['user_email'] = $this->user_email; - $array['users'][0]['password'] = password_hash($this->password, PASSWORD_DEFAULT, $options); - $array['users'][0]['salt'] = null; + //build user insert array + $array = []; + $array['users'][0]['user_uuid'] = $this->user_uuid; + $array['users'][0]['domain_uuid'] = $this->domain_uuid; + $array['users'][0]['user_email'] = $this->user_email; + $array['users'][0]['password'] = password_hash($this->password, PASSWORD_DEFAULT, $options); + $array['users'][0]['salt'] = null; - //build user group insert array - $array['user_groups'][0]['user_group_uuid'] = uuid(); - $array['user_groups'][0]['domain_uuid'] = $this->domain_uuid; - $array['user_groups'][0]['group_name'] = 'user'; - $array['user_groups'][0]['user_uuid'] = $this->user_uuid; + //build user group insert array + $array['user_groups'][0]['user_group_uuid'] = uuid(); + $array['user_groups'][0]['domain_uuid'] = $this->domain_uuid; + $array['user_groups'][0]['group_name'] = 'user'; + $array['user_groups'][0]['user_uuid'] = $this->user_uuid; - //grant temporary permissions - $p = permissions::new(); - $p->add('user_edit', 'temp'); + //grant temporary permissions + $p = permissions::new(); + $p->add('user_edit', 'temp'); - //execute insert - $settings->database()->app_name = 'authentication'; - $settings->database()->app_uuid = 'a8a12918-69a4-4ece-a1ae-3932be0e41f1'; - $settings->database()->save($array); - unset($array); + //execute insert + $settings->database()->app_name = 'authentication'; + $settings->database()->app_uuid = 'a8a12918-69a4-4ece-a1ae-3932be0e41f1'; + $settings->database()->save($array); + unset($array); - //revoke temporary permissions - $p->delete('user_edit', 'temp'); + //revoke temporary permissions + $p->delete('user_edit', 'temp'); - } - - } - - //result array - if ($valid_password) { - $result["plugin"] = "database"; - $result["domain_name"] = $this->domain_name; - $result["username"] = $this->username; - $result["user_uuid"] = $this->user_uuid; - $result["domain_uuid"] = $_SESSION['domain_uuid']; - $result["contact_uuid"] = $this->contact_uuid; - if ($contacts_exists) { - $result["contact_organization"] = $this->contact_organization; - $result["contact_name_given"] = $this->contact_name_given; - $result["contact_name_family"] = $this->contact_name_family; - $result["contact_image"] = $this->contact_image; - } - $result["user_email"] = $this->user_email; - $result["sql"] = $sql; - $result["authorized"] = $valid_password; - } - - //return the results - return $result ?? false; + } } + //result array + if ($valid_password) { + $result["plugin"] = "database"; + $result["domain_name"] = $this->domain_name; + $result["username"] = $this->username; + $result["user_uuid"] = $this->user_uuid; + $result["domain_uuid"] = $_SESSION['domain_uuid']; + $result["contact_uuid"] = $this->contact_uuid; + if ($contacts_exists) { + $result["contact_organization"] = $this->contact_organization; + $result["contact_name_given"] = $this->contact_name_given; + $result["contact_name_family"] = $this->contact_name_family; + $result["contact_image"] = $this->contact_image; + } + $result["user_email"] = $this->user_email; + $result["sql"] = $sql; + $result["authorized"] = $valid_password; + } + + //return the results + return $result ?? false; + + } return; diff --git a/core/authentication/resources/classes/plugins/email.php b/core/authentication/resources/classes/plugins/email.php index 2e826cd0f4..6a960b446e 100644 --- a/core/authentication/resources/classes/plugins/email.php +++ b/core/authentication/resources/classes/plugins/email.php @@ -60,405 +60,401 @@ class plugin_email { /** * time based one time password with email + * * @return array [authorized] => true or false */ function email(authentication $auth, settings $settings) { //pre-process some settings - $theme_favicon = $settings->get('theme', 'favicon', PROJECT_PATH.'/themes/default/favicon.ico'); - $theme_logo = $settings->get('theme', 'logo', PROJECT_PATH.'/themes/default/images/logo_login.png'); - $theme_login_type = $settings->get('theme', 'login_brand_type', ''); - $theme_login_image = $settings->get('theme', 'login_brand_image', ''); - $theme_login_text = $settings->get('theme', 'login_brand_text', ''); - $theme_login_logo_width = $settings->get('theme', 'login_logo_width', 'auto; max-width: 300px'); - $theme_login_logo_height = $settings->get('theme', 'login_logo_height', 'auto; max-height: 300px'); - $theme_message_delay = 1000 * (float)$settings->get('theme', 'message_delay', 3000); - $background_videos = $settings->get('theme', 'background_video', null); - $theme_background_video = (isset($background_videos) && is_array($background_videos)) ? $background_videos[0] : null; - //$login_domain_name_visible = $settings->get('login', 'domain_name_visible'); - //$login_domain_name = $settings->get('login', 'domain_name'); - $login_destination = $settings->get('login', 'destination'); - $users_unique = $settings->get('users', 'unique', ''); + $theme_favicon = $settings->get('theme', 'favicon', PROJECT_PATH . '/themes/default/favicon.ico'); + $theme_logo = $settings->get('theme', 'logo', PROJECT_PATH . '/themes/default/images/logo_login.png'); + $theme_login_type = $settings->get('theme', 'login_brand_type', ''); + $theme_login_image = $settings->get('theme', 'login_brand_image', ''); + $theme_login_text = $settings->get('theme', 'login_brand_text', ''); + $theme_login_logo_width = $settings->get('theme', 'login_logo_width', 'auto; max-width: 300px'); + $theme_login_logo_height = $settings->get('theme', 'login_logo_height', 'auto; max-height: 300px'); + $theme_message_delay = 1000 * (float)$settings->get('theme', 'message_delay', 3000); + $background_videos = $settings->get('theme', 'background_video', null); + $theme_background_video = (isset($background_videos) && is_array($background_videos)) ? $background_videos[0] : null; + //$login_domain_name_visible = $settings->get('login', 'domain_name_visible'); + //$login_domain_name = $settings->get('login', 'domain_name'); + $login_destination = $settings->get('login', 'destination'); + $users_unique = $settings->get('users', 'unique', ''); //get the domain - $domain_array = explode(":", $_SERVER["HTTP_HOST"]); - $domain_name = $domain_array[0]; + $domain_array = explode(":", $_SERVER["HTTP_HOST"]); + $domain_name = $domain_array[0]; //use the session username - if (isset($_SESSION['username'])) { - $_POST['username'] = $_SESSION['username']; - $_REQUEST['username'] = $_SESSION['username']; - } + if (isset($_SESSION['username'])) { + $_POST['username'] = $_SESSION['username']; + $_REQUEST['username'] = $_SESSION['username']; + } //request the username - if (!isset($_POST['username']) && !isset($_POST['authentication_code'])) { + if (!isset($_POST['username']) && !isset($_POST['authentication_code'])) { - //add multi-lingual support - $language = new text; - $text = $language->get(null, '/core/authentication'); + //add multi-lingual support + $language = new text; + $text = $language->get(null, '/core/authentication'); - //initialize a template object - $view = new template(); - $view->engine = 'smarty'; - $view->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/authentication/resources/views/'; - $view->cache_dir = sys_get_temp_dir(); - $view->init(); + //initialize a template object + $view = new template(); + $view->engine = 'smarty'; + $view->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/authentication/resources/views/'; + $view->cache_dir = sys_get_temp_dir(); + $view->init(); - //assign default values to the template - $view->assign("project_path", PROJECT_PATH); - $view->assign("login_destination_url", $login_destination); - $view->assign("favicon", $theme_favicon); - $view->assign("login_title", $text['label-username']); - $view->assign("login_username", $text['label-username']); - $view->assign("login_logo_width", $theme_login_logo_width); - $view->assign("login_logo_height", $theme_login_logo_height); - $view->assign("login_logo_source", $theme_logo); - $view->assign("button_login", $text['button-login']); - $view->assign("message_delay", $theme_message_delay); - $view->assign("background_video", $theme_background_video); + //assign default values to the template + $view->assign("project_path", PROJECT_PATH); + $view->assign("login_destination_url", $login_destination); + $view->assign("favicon", $theme_favicon); + $view->assign("login_title", $text['label-username']); + $view->assign("login_username", $text['label-username']); + $view->assign("login_logo_width", $theme_login_logo_width); + $view->assign("login_logo_height", $theme_login_logo_height); + $view->assign("login_logo_source", $theme_logo); + $view->assign("button_login", $text['button-login']); + $view->assign("message_delay", $theme_message_delay); + $view->assign("background_video", $theme_background_video); - //messages - $view->assign('messages', message::html(true, ' ')); + //messages + $view->assign('messages', message::html(true, ' ')); - //show the views - $content = $view->render('username.htm'); - echo $content; - exit; + //show the views + $content = $view->render('username.htm'); + echo $content; + exit; - } + } //show the authentication code view - if (!isset($_POST['authentication_code'])) { + if (!isset($_POST['authentication_code'])) { - //get the username - //if (!isset($this->username) && isset($_REQUEST['username'])) { - // $this->username = $_REQUEST['username']; - //} + //get the username + //if (!isset($this->username) && isset($_REQUEST['username'])) { + // $this->username = $_REQUEST['username']; + //} - //get the user details - $sql = "select user_uuid, username, user_email, contact_uuid \n"; - $sql .= "from v_users\n"; - $sql .= "where (\n"; - $sql .= " username = :username\n"; - $sql .= " or user_email = :username\n"; - $sql .= ")\n"; - if ($users_unique != "global") { - //unique username per domain (not globally unique across system - example: email address) - $sql .= "and domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; - } - $sql .= "and (user_type = 'default' or user_type is null) "; - $parameters['username'] = $_REQUEST['username']; - $row = $this->database->select($sql, $parameters, 'row'); - unset($parameters); - - //set class variables - //if (!empty($row["user_email"])) { - // $this->user_uuid = $row['user_uuid']; - // $this->user_email = $row['user_email']; - // $this->contact_uuid = $row['contact_uuid']; - //} - - //set a few session variables - $_SESSION["user_uuid"] = $row['user_uuid']; - $_SESSION["username"] = $row['username']; - $_SESSION["user_email"] = $row['user_email']; - $_SESSION["contact_uuid"] = $row["contact_uuid"]; - - //user not found - if (empty($row) || !is_array($row) || @sizeof($row) == 0) { - //clear submitted usernames - unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); - - //clear authentication session - unset($_SESSION['authentication']); - - //build the result array - $result["plugin"] = "email"; - $result["domain_uuid"] = $_SESSION["domain_uuid"]; - $result["domain_name"] = $_SESSION["domain_name"]; - $result["authorized"] = false; - - //retun the array - return $result; - } - - //user email not found - else if (empty($row["user_email"])) { - //clear submitted usernames - unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); - - //clear authentication session - unset($_SESSION['authentication']); - - //build the result array - $result["plugin"] = "email"; - $result["domain_name"] = $_SESSION["domain_name"]; - $result["username"] = $_REQUEST['username']; - $result["user_uuid"] = $_SESSION["user_uuid"]; - $result["domain_uuid"] = $_SESSION["domain_uuid"]; - $result["contact_uuid"] = $_SESSION["contact_uuid"]; - $result["authorized"] = false; - - //add the failed login to user logs - user_logs::add($result); - - //return the array - return $result; - } - - //authentication code - $_SESSION["user"]["authentication"]["email"]["code"] = generate_password(6, 1); - $_SESSION["user"]["authentication"]["email"]["epoch"] = time(); - - //$_SESSION["authentication_address"] = $_SERVER['REMOTE_ADDR']; - //$_SESSION["authentication_date"] = 'now()'; - - //set the authentication code - //$sql = "update v_users \n"; - //$sql .= "set auth_code = :auth_code \n"; - //$sql .= "where user_uuid = :user_uuid;"; - //$parameters['auth_code'] = $auth_code_hash; - //$parameters['user_uuid'] = $this->user_uuid; - //$this->database->execute($sql, $parameters); - //unset($sql); - - //email settings - //$email_address = $this->user_email; - //$email_subject = 'Validation Code'; - //$email_body = 'Validation Code: '.$authentication_code; - - //send email with the authentication_code - //ob_start(); - //$sent = !send_email($email_address, $email_subject, $email_body, $email_error, null, null, 3, 3) ? false : true; - //$response = ob_get_clean(); - - //get the language code - $language_code = $settings->get('domain', 'language', 'en-us'); - - //get the email template from the database - $sql = "select template_subject, template_body "; - $sql .= "from v_email_templates "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and template_language = :template_language "; - $sql .= "and template_category = :template_category "; - $sql .= "and template_subcategory = :template_subcategory "; - $sql .= "and template_type = :template_type "; - $sql .= "and template_enabled = true "; + //get the user details + $sql = "select user_uuid, username, user_email, contact_uuid \n"; + $sql .= "from v_users\n"; + $sql .= "where (\n"; + $sql .= " username = :username\n"; + $sql .= " or user_email = :username\n"; + $sql .= ")\n"; + if ($users_unique != "global") { + //unique username per domain (not globally unique across system - example: email address) + $sql .= "and domain_uuid = :domain_uuid "; $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; - $parameters['template_language'] = $language_code; - $parameters['template_category'] = 'authentication'; - $parameters['template_subcategory'] = 'email'; - $parameters['template_type'] = 'html'; - $row = $this->database->select($sql, $parameters, 'row'); - $email_subject = $row['template_subject']; - $email_body = $row['template_body']; - unset($sql, $parameters, $row); + } + $sql .= "and (user_type = 'default' or user_type is null) "; + $parameters['username'] = $_REQUEST['username']; + $row = $this->database->select($sql, $parameters, 'row'); + unset($parameters); - //replace variables in email subject - $email_subject = str_replace('${domain_name}', $_SESSION["domain_name"], $email_subject); + //set class variables + //if (!empty($row["user_email"])) { + // $this->user_uuid = $row['user_uuid']; + // $this->user_email = $row['user_email']; + // $this->contact_uuid = $row['contact_uuid']; + //} - //replace variables in email body - $email_body = str_replace('${domain_name}', $_SESSION["domain_name"], $email_body); - $email_body = str_replace('${auth_code}', $_SESSION["user"]["authentication"]["email"]["code"], $email_body); + //set a few session variables + $_SESSION["user_uuid"] = $row['user_uuid']; + $_SESSION["username"] = $row['username']; + $_SESSION["user_email"] = $row['user_email']; + $_SESSION["contact_uuid"] = $row["contact_uuid"]; - //get the email from name and address - $email_from_address = $_SESSION['email']['smtp_from']['text']; - $email_from_name = $_SESSION['email']['smtp_from_name']['text']; + //user not found + if (empty($row) || !is_array($row) || @sizeof($row) == 0) { + //clear submitted usernames + unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); - //get the email send mode options: direct or email_queue - $email_send_mode = $_SESSION['authentication']['email_send_mode']['text'] ?? 'email_queue'; + //clear authentication session + unset($_SESSION['authentication']); - //send the email - if ($email_send_mode == 'email_queue') { - //set the variables - $email_queue_uuid = uuid(); - $email_uuid = uuid(); - $hostname = gethostname(); + //build the result array + $result["plugin"] = "email"; + $result["domain_uuid"] = $_SESSION["domain_uuid"]; + $result["domain_name"] = $_SESSION["domain_name"]; + $result["authorized"] = false; - //add the temporary permissions - $p = permissions::new(); - $p->add("email_queue_add", 'temp'); - $p->add("email_queue_edit", 'temp'); + //retun the array + return $result; + } //user email not found + elseif (empty($row["user_email"])) { + //clear submitted usernames + unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); - $array['email_queue'][0]["email_queue_uuid"] = $email_queue_uuid; - $array['email_queue'][0]["domain_uuid"] = $_SESSION["domain_uuid"]; - $array['email_queue'][0]["hostname"] = $hostname; - $array['email_queue'][0]["email_date"] = 'now()'; - $array['email_queue'][0]["email_from"] = $email_from_address; - $array['email_queue'][0]["email_to"] = $_SESSION["user_email"]; - $array['email_queue'][0]["email_subject"] = $email_subject; - $array['email_queue'][0]["email_body"] = $email_body; - $array['email_queue'][0]["email_status"] = 'waiting'; - $array['email_queue'][0]["email_retry_count"] = 3; - $array['email_queue'][0]["email_uuid"] = $email_uuid; - $array['email_queue'][0]["email_action_before"] = null; - $array['email_queue'][0]["email_action_after"] = null; - $this->database->save($array); - $err = $this->database->message; - unset($array); + //clear authentication session + unset($_SESSION['authentication']); - //remove the temporary permission - $p->delete("email_queue_add", 'temp'); - $p->delete("email_queue_edit", 'temp'); - } - else { - //send email - direct - $email = new email; - $email->recipients = $_SESSION["user_email"]; - $email->subject = $email_subject; - $email->body = $email_body; - $email->from_address = $email_from_address; - $email->from_name = $email_from_name; - //$email->attachments = $email_attachments; - $email->debug_level = 0; - $email->method = 'direct'; - $sent = $email->send(); - } + //build the result array + $result["plugin"] = "email"; + $result["domain_name"] = $_SESSION["domain_name"]; + $result["username"] = $_REQUEST['username']; + $result["user_uuid"] = $_SESSION["user_uuid"]; + $result["domain_uuid"] = $_SESSION["domain_uuid"]; + $result["contact_uuid"] = $_SESSION["contact_uuid"]; + $result["authorized"] = false; - //debug informations - //$email_response = $email->response; - //$email_error = $email->email_error; - //echo $email_response."
\n"; - //echo $email_error."
\n"; + //add the failed login to user logs + user_logs::add($result); - //get the domain - $domain_array = explode(":", $_SERVER["HTTP_HOST"]); - $domain_name = $domain_array[0]; + //return the array + return $result; + } - //create token - //$object = new token; - //$token = $object->create('login'); + //authentication code + $_SESSION["user"]["authentication"]["email"]["code"] = generate_password(6, 1); + $_SESSION["user"]["authentication"]["email"]["epoch"] = time(); - //add multi-lingual support - $language = new text; - $text = $language->get(null, '/core/authentication'); + //$_SESSION["authentication_address"] = $_SERVER['REMOTE_ADDR']; + //$_SESSION["authentication_date"] = 'now()'; - //initialize a template object - $view = new template(); - $view->engine = 'smarty'; - $view->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/authentication/resources/views/'; - $view->cache_dir = sys_get_temp_dir(); - $view->init(); + //set the authentication code + //$sql = "update v_users \n"; + //$sql .= "set auth_code = :auth_code \n"; + //$sql .= "where user_uuid = :user_uuid;"; + //$parameters['auth_code'] = $auth_code_hash; + //$parameters['user_uuid'] = $this->user_uuid; + //$this->database->execute($sql, $parameters); + //unset($sql); - //assign default values to the template - $view->assign("project_path", PROJECT_PATH); - $view->assign("login_destination_url", $login_destination); - $view->assign("favicon", $theme_favicon); - $view->assign("login_title", $text['label-verify']); - $view->assign("login_email_description", $text['label-email_description']); - $view->assign("login_authentication_code", $text['label-authentication_code']); - $view->assign("login_logo_width", $theme_login_logo_width); - $view->assign("login_logo_height", $theme_login_logo_height); - $view->assign("login_logo_source", $theme_logo); - $view->assign("button_verify", $text['label-verify']); - $view->assign("message_delay", $theme_message_delay); - if (!empty($_SESSION['username'])) { - $view->assign("username", $_SESSION['username']); - $view->assign("button_cancel", $text['button-cancel']); - } + //email settings + //$email_address = $this->user_email; + //$email_subject = 'Validation Code'; + //$email_body = 'Validation Code: '.$authentication_code; - //messages - $view->assign('messages', message::html(true, ' ')); + //send email with the authentication_code + //ob_start(); + //$sent = !send_email($email_address, $email_subject, $email_body, $email_error, null, null, 3, 3) ? false : true; + //$response = ob_get_clean(); - //show the views - $content = $view->render('email.htm'); - echo $content; + //get the language code + $language_code = $settings->get('domain', 'language', 'en-us'); + + //get the email template from the database + $sql = "select template_subject, template_body "; + $sql .= "from v_email_templates "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and template_language = :template_language "; + $sql .= "and template_category = :template_category "; + $sql .= "and template_subcategory = :template_subcategory "; + $sql .= "and template_type = :template_type "; + $sql .= "and template_enabled = true "; + $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; + $parameters['template_language'] = $language_code; + $parameters['template_category'] = 'authentication'; + $parameters['template_subcategory'] = 'email'; + $parameters['template_type'] = 'html'; + $row = $this->database->select($sql, $parameters, 'row'); + $email_subject = $row['template_subject']; + $email_body = $row['template_body']; + unset($sql, $parameters, $row); + + //replace variables in email subject + $email_subject = str_replace('${domain_name}', $_SESSION["domain_name"], $email_subject); + + //replace variables in email body + $email_body = str_replace('${domain_name}', $_SESSION["domain_name"], $email_body); + $email_body = str_replace('${auth_code}', $_SESSION["user"]["authentication"]["email"]["code"], $email_body); + + //get the email from name and address + $email_from_address = $_SESSION['email']['smtp_from']['text']; + $email_from_name = $_SESSION['email']['smtp_from_name']['text']; + + //get the email send mode options: direct or email_queue + $email_send_mode = $_SESSION['authentication']['email_send_mode']['text'] ?? 'email_queue'; + + //send the email + if ($email_send_mode == 'email_queue') { + //set the variables + $email_queue_uuid = uuid(); + $email_uuid = uuid(); + $hostname = gethostname(); + + //add the temporary permissions + $p = permissions::new(); + $p->add("email_queue_add", 'temp'); + $p->add("email_queue_edit", 'temp'); + + $array['email_queue'][0]["email_queue_uuid"] = $email_queue_uuid; + $array['email_queue'][0]["domain_uuid"] = $_SESSION["domain_uuid"]; + $array['email_queue'][0]["hostname"] = $hostname; + $array['email_queue'][0]["email_date"] = 'now()'; + $array['email_queue'][0]["email_from"] = $email_from_address; + $array['email_queue'][0]["email_to"] = $_SESSION["user_email"]; + $array['email_queue'][0]["email_subject"] = $email_subject; + $array['email_queue'][0]["email_body"] = $email_body; + $array['email_queue'][0]["email_status"] = 'waiting'; + $array['email_queue'][0]["email_retry_count"] = 3; + $array['email_queue'][0]["email_uuid"] = $email_uuid; + $array['email_queue'][0]["email_action_before"] = null; + $array['email_queue'][0]["email_action_after"] = null; + $this->database->save($array); + $err = $this->database->message; + unset($array); + + //remove the temporary permission + $p->delete("email_queue_add", 'temp'); + $p->delete("email_queue_edit", 'temp'); + } else { + //send email - direct + $email = new email; + $email->recipients = $_SESSION["user_email"]; + $email->subject = $email_subject; + $email->body = $email_body; + $email->from_address = $email_from_address; + $email->from_name = $email_from_name; + //$email->attachments = $email_attachments; + $email->debug_level = 0; + $email->method = 'direct'; + $sent = $email->send(); + } + + //debug informations + //$email_response = $email->response; + //$email_error = $email->email_error; + //echo $email_response."
\n"; + //echo $email_error."
\n"; + + //get the domain + $domain_array = explode(":", $_SERVER["HTTP_HOST"]); + $domain_name = $domain_array[0]; + + //create token + //$object = new token; + //$token = $object->create('login'); + + //add multi-lingual support + $language = new text; + $text = $language->get(null, '/core/authentication'); + + //initialize a template object + $view = new template(); + $view->engine = 'smarty'; + $view->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/authentication/resources/views/'; + $view->cache_dir = sys_get_temp_dir(); + $view->init(); + + //assign default values to the template + $view->assign("project_path", PROJECT_PATH); + $view->assign("login_destination_url", $login_destination); + $view->assign("favicon", $theme_favicon); + $view->assign("login_title", $text['label-verify']); + $view->assign("login_email_description", $text['label-email_description']); + $view->assign("login_authentication_code", $text['label-authentication_code']); + $view->assign("login_logo_width", $theme_login_logo_width); + $view->assign("login_logo_height", $theme_login_logo_height); + $view->assign("login_logo_source", $theme_logo); + $view->assign("button_verify", $text['label-verify']); + $view->assign("message_delay", $theme_message_delay); + if (!empty($_SESSION['username'])) { + $view->assign("username", $_SESSION['username']); + $view->assign("button_cancel", $text['button-cancel']); + } + + //messages + $view->assign('messages', message::html(true, ' ')); + + //show the views + $content = $view->render('email.htm'); + echo $content; + exit; + } + + //if authorized then verify + if (isset($_POST['authentication_code'])) { + + //check if the authentication code has expired. if expired return false + if (!empty($_SESSION["user"]) && $_SESSION["user"]["authentication"]["email"]["epoch"] + 3 > time()) { + //authentication code expired + $result["plugin"] = "email"; + $result["domain_name"] = $_SESSION["domain_name"]; + $result["username"] = $_SESSION["username"]; + $result["error_message"] = 'code expired'; + $result["authorized"] = false; + print_r($result); + return $result; exit; } - //if authorized then verify - if (isset($_POST['authentication_code'])) { + //get the user details + $sql = "select user_uuid, user_email, contact_uuid\n"; + $sql .= "from v_users\n"; + $sql .= "where (\n"; + $sql .= " username = :username\n"; + $sql .= " or user_email = :username\n"; + $sql .= ")\n"; + if ($users_unique != "global") { + //unique username per domain (not globally unique across system - example: email address) + $sql .= "and domain_uuid = :domain_uuid "; + $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; + } + $parameters['username'] = $_SESSION["username"]; + $row = $this->database->select($sql, $parameters, 'row'); + $this->user_uuid = $row['user_uuid']; + $this->user_email = $row['user_email']; + $this->contact_uuid = $row['contact_uuid']; + unset($parameters); + /* + echo 'session code = '.$_SESSION["user"]["authentication"]["email"]["code"].'
'; + echo 'post code = '.$_POST['authentication_code'].'
'; + exit; + */ - //check if the authentication code has expired. if expired return false - if (!empty($_SESSION["user"]) && $_SESSION["user"]["authentication"]["email"]["epoch"] + 3 > time()) { - //authentication code expired - $result["plugin"] = "email"; - $result["domain_name"] = $_SESSION["domain_name"]; - $result["username"] = $_SESSION["username"]; - $result["error_message"] = 'code expired'; - $result["authorized"] = false; - print_r($result); - return $result; - exit; + //validate the code + if (!empty($_SESSION["user"]) && $_SESSION["user"]["authentication"]["email"]["code"] === $_POST['authentication_code']) { + $auth_valid = true; + } else { + $auth_valid = false; + } + + //clear posted authentication code + unset($_POST['authentication_code']); + + //check if contacts app exists + $contacts_exists = file_exists($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/contacts/') ? true : false; + + //get the user details + if ($auth_valid) { + //get user data from the database + $sql = "select "; + $sql .= " u.user_uuid, "; + $sql .= " u.username, "; + $sql .= " u.user_email, "; + $sql .= " u.contact_uuid "; + if ($contacts_exists) { + $sql .= ","; + $sql .= "c.contact_organization, "; + $sql .= "c.contact_name_given, "; + $sql .= "c.contact_name_family, "; + $sql .= "a.contact_attachment_uuid "; } - - //get the user details - $sql = "select user_uuid, user_email, contact_uuid\n"; - $sql .= "from v_users\n"; - $sql .= "where (\n"; - $sql .= " username = :username\n"; - $sql .= " or user_email = :username\n"; - $sql .= ")\n"; + $sql .= "from "; + $sql .= " v_users as u "; + if ($contacts_exists) { + $sql .= "left join v_contacts as c on u.contact_uuid = c.contact_uuid and u.contact_uuid is not null "; + $sql .= "left join v_contact_attachments as a on u.contact_uuid = a.contact_uuid and u.contact_uuid is not null and a.attachment_primary = true and a.attachment_filename is not null and a.attachment_content is not null "; + } + $sql .= "where "; + $sql .= " u.user_uuid = :user_uuid "; if ($users_unique != "global") { //unique username per domain (not globally unique across system - example: email address) - $sql .= "and domain_uuid = :domain_uuid "; + $sql .= "and u.domain_uuid = :domain_uuid "; $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; } - $parameters['username'] = $_SESSION["username"]; - $row = $this->database->select($sql, $parameters, 'row'); - $this->user_uuid = $row['user_uuid']; - $this->user_email = $row['user_email']; - $this->contact_uuid = $row['contact_uuid']; + $parameters['user_uuid'] = $_SESSION["user_uuid"]; + $row = $this->database->select($sql, $parameters, 'row'); unset($parameters); - /* - echo 'session code = '.$_SESSION["user"]["authentication"]["email"]["code"].'
'; - echo 'post code = '.$_POST['authentication_code'].'
'; - exit; - */ - //validate the code - if (!empty($_SESSION["user"]) && $_SESSION["user"]["authentication"]["email"]["code"] === $_POST['authentication_code']) { - $auth_valid = true; - } - else { - $auth_valid = false; - } - - //clear posted authentication code - unset($_POST['authentication_code']); - - //check if contacts app exists - $contacts_exists = file_exists($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/contacts/') ? true : false; - - //get the user details - if ($auth_valid) { - //get user data from the database - $sql = "select "; - $sql .= " u.user_uuid, "; - $sql .= " u.username, "; - $sql .= " u.user_email, "; - $sql .= " u.contact_uuid "; - if ($contacts_exists) { - $sql .= ","; - $sql .= "c.contact_organization, "; - $sql .= "c.contact_name_given, "; - $sql .= "c.contact_name_family, "; - $sql .= "a.contact_attachment_uuid "; - } - $sql .= "from "; - $sql .= " v_users as u "; - if ($contacts_exists) { - $sql .= "left join v_contacts as c on u.contact_uuid = c.contact_uuid and u.contact_uuid is not null "; - $sql .= "left join v_contact_attachments as a on u.contact_uuid = a.contact_uuid and u.contact_uuid is not null and a.attachment_primary = true and a.attachment_filename is not null and a.attachment_content is not null "; - } - $sql .= "where "; - $sql .= " u.user_uuid = :user_uuid "; - if ($users_unique != "global") { - //unique username per domain (not globally unique across system - example: email address) - $sql .= "and u.domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; - } - $parameters['user_uuid'] = $_SESSION["user_uuid"]; - $row = $this->database->select($sql, $parameters, 'row'); - unset($parameters); - - //set a few session variables - //$_SESSION["username"] = $row['username']; //setting the username makes it skip the rest of the authentication - //$_SESSION["user_email"] = $row['user_email']; - //$_SESSION["contact_uuid"] = $row["contact_uuid"]; - } - else { + //set a few session variables + //$_SESSION["username"] = $row['username']; //setting the username makes it skip the rest of the authentication + //$_SESSION["user_email"] = $row['user_email']; + //$_SESSION["contact_uuid"] = $row["contact_uuid"]; + } else { // //destroy session // session_unset(); // session_destroy(); @@ -472,65 +468,65 @@ class plugin_email { // //exit the code // exit(); - //clear submitted usernames - unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); + //clear submitted usernames + unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); - //clear authentication session - unset($_SESSION['authentication']); + //clear authentication session + unset($_SESSION['authentication']); - } - - /* - //check if user successfully logged in during the interval - //$sql = "select user_log_uuid, timestamp, user_name, user_agent, remote_address "; - $sql = "select count(*) as count "; - $sql .= "from v_user_logs "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and user_uuid = :user_uuid "; - $sql .= "and user_agent = :user_agent "; - $sql .= "and type = 'login' "; - $sql .= "and result = 'success' "; - $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) > 3 "; - $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) < 300 "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['user_uuid'] = $this->user_uuid; - $parameters['user_agent'] = $_SERVER['HTTP_USER_AGENT']; - $user_log_count = $this->database->select($sql, $parameters, 'all'); - //view_array($user_log_count); - unset($sql, $parameters); - */ - - //result array - $result["plugin"] = "email"; - $result["domain_name"] = $_SESSION["domain_name"]; - $result["username"] = $_SESSION["username"]; - $result["user_uuid"] = $_SESSION["user_uuid"]; - $result["domain_uuid"] = $_SESSION["domain_uuid"]; - if ($contacts_exists) { - $result["contact_uuid"] = $_SESSION["contact_uuid"]; - $result["contact_organization"] = $row["contact_organization"]; - $result["contact_name_given"] = $row["contact_name_given"]; - $result["contact_name_family"] = $row["contact_name_family"]; - $result["contact_image"] = $row["contact_attachment_uuid"]; - } - $result["authorized"] = $auth_valid ? true : false; - - //add the failed login to user logs - if (!$auth_valid) { - user_logs::add($result); - } - - //retun the array - return $result; - - //$_SESSION['authentication']['plugin']['email']['plugin'] = "email"; - //$_SESSION['authentication']['plugin']['email']['domain_name'] = $_SESSION["domain_name"]; - //$_SESSION['authentication']['plugin']['email']['username'] = $row['username']; - //$_SESSION['authentication']['plugin']['email']['user_uuid'] = $_SESSION["user_uuid"]; - //$_SESSION['authentication']['plugin']['email']['contact_uuid'] = $_SESSION["contact_uuid"]; - //$_SESSION['authentication']['plugin']['email']['domain_uuid'] = $_SESSION["domain_uuid"]; - //$_SESSION['authentication']['plugin']['email']['authorized'] = $auth_valid ? true : false; } + /* + //check if user successfully logged in during the interval + //$sql = "select user_log_uuid, timestamp, user_name, user_agent, remote_address "; + $sql = "select count(*) as count "; + $sql .= "from v_user_logs "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and user_uuid = :user_uuid "; + $sql .= "and user_agent = :user_agent "; + $sql .= "and type = 'login' "; + $sql .= "and result = 'success' "; + $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) > 3 "; + $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) < 300 "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['user_uuid'] = $this->user_uuid; + $parameters['user_agent'] = $_SERVER['HTTP_USER_AGENT']; + $user_log_count = $this->database->select($sql, $parameters, 'all'); + //view_array($user_log_count); + unset($sql, $parameters); + */ + + //result array + $result["plugin"] = "email"; + $result["domain_name"] = $_SESSION["domain_name"]; + $result["username"] = $_SESSION["username"]; + $result["user_uuid"] = $_SESSION["user_uuid"]; + $result["domain_uuid"] = $_SESSION["domain_uuid"]; + if ($contacts_exists) { + $result["contact_uuid"] = $_SESSION["contact_uuid"]; + $result["contact_organization"] = $row["contact_organization"]; + $result["contact_name_given"] = $row["contact_name_given"]; + $result["contact_name_family"] = $row["contact_name_family"]; + $result["contact_image"] = $row["contact_attachment_uuid"]; + } + $result["authorized"] = $auth_valid ? true : false; + + //add the failed login to user logs + if (!$auth_valid) { + user_logs::add($result); + } + + //retun the array + return $result; + + //$_SESSION['authentication']['plugin']['email']['plugin'] = "email"; + //$_SESSION['authentication']['plugin']['email']['domain_name'] = $_SESSION["domain_name"]; + //$_SESSION['authentication']['plugin']['email']['username'] = $row['username']; + //$_SESSION['authentication']['plugin']['email']['user_uuid'] = $_SESSION["user_uuid"]; + //$_SESSION['authentication']['plugin']['email']['contact_uuid'] = $_SESSION["contact_uuid"]; + //$_SESSION['authentication']['plugin']['email']['domain_uuid'] = $_SESSION["domain_uuid"]; + //$_SESSION['authentication']['plugin']['email']['authorized'] = $auth_valid ? true : false; + } + } } diff --git a/core/authentication/resources/classes/plugins/ldap.php b/core/authentication/resources/classes/plugins/ldap.php index 2d16a68cd3..514a933c2c 100644 --- a/core/authentication/resources/classes/plugins/ldap.php +++ b/core/authentication/resources/classes/plugins/ldap.php @@ -27,6 +27,7 @@ class plugin_ldap { */ private $database; + /** * Called when the object is created */ diff --git a/core/authentication/resources/classes/plugins/totp.php b/core/authentication/resources/classes/plugins/totp.php index 8ac120707a..b214ef8ce1 100644 --- a/core/authentication/resources/classes/plugins/totp.php +++ b/core/authentication/resources/classes/plugins/totp.php @@ -65,325 +65,322 @@ class plugin_totp { /** * time based one time password aka totp + * * @return array [authorized] => true or false */ function totp(authentication $auth, settings $settings) { //pre-process some settings - $theme_favicon = $settings->get('theme', 'favicon', PROJECT_PATH.'/themes/default/favicon.ico'); - $theme_logo = $settings->get('theme', 'logo', PROJECT_PATH.'/themes/default/images/logo_login.png'); - $theme_login_type = $settings->get('theme', 'login_brand_type', ''); - $theme_login_image = $settings->get('theme', 'login_brand_image', ''); - $theme_login_text = $settings->get('theme', 'login_brand_text', ''); - $theme_login_logo_width = $settings->get('theme', 'login_logo_width', 'auto; max-width: 300px'); - $theme_login_logo_height = $settings->get('theme', 'login_logo_height', 'auto; max-height: 300px'); - $theme_message_delay = 1000 * (float)$settings->get('theme', 'message_delay', 3000); - $background_videos = $settings->get('theme', 'background_video', null); - $theme_background_video = (isset($background_videos) && is_array($background_videos)) ? $background_videos[0] : null; - //$login_domain_name_visible = $settings->get('login', 'domain_name_visible'); - //$login_domain_name = $settings->get('login', 'domain_name'); - $login_destination = $settings->get('login', 'destination'); - $users_unique = $settings->get('users', 'unique', ''); + $theme_favicon = $settings->get('theme', 'favicon', PROJECT_PATH . '/themes/default/favicon.ico'); + $theme_logo = $settings->get('theme', 'logo', PROJECT_PATH . '/themes/default/images/logo_login.png'); + $theme_login_type = $settings->get('theme', 'login_brand_type', ''); + $theme_login_image = $settings->get('theme', 'login_brand_image', ''); + $theme_login_text = $settings->get('theme', 'login_brand_text', ''); + $theme_login_logo_width = $settings->get('theme', 'login_logo_width', 'auto; max-width: 300px'); + $theme_login_logo_height = $settings->get('theme', 'login_logo_height', 'auto; max-height: 300px'); + $theme_message_delay = 1000 * (float)$settings->get('theme', 'message_delay', 3000); + $background_videos = $settings->get('theme', 'background_video', null); + $theme_background_video = (isset($background_videos) && is_array($background_videos)) ? $background_videos[0] : null; + //$login_domain_name_visible = $settings->get('login', 'domain_name_visible'); + //$login_domain_name = $settings->get('login', 'domain_name'); + $login_destination = $settings->get('login', 'destination'); + $users_unique = $settings->get('users', 'unique', ''); //get the username - if (isset($_SESSION["username"])) { - $this->username = $_SESSION["username"]; - } - if (isset($_POST['username'])) { - $this->username = $_POST['username']; - $_SESSION["username"] = $this->username; - } + if (isset($_SESSION["username"])) { + $this->username = $_SESSION["username"]; + } + if (isset($_POST['username'])) { + $this->username = $_POST['username']; + $_SESSION["username"] = $this->username; + } //request the username - if (!$this->username && !isset($_POST['authentication_code'])) { + if (!$this->username && !isset($_POST['authentication_code'])) { - //get the domain - $domain_array = explode(":", $_SERVER["HTTP_HOST"]); - $domain_name = $domain_array[0]; + //get the domain + $domain_array = explode(":", $_SERVER["HTTP_HOST"]); + $domain_name = $domain_array[0]; - //create token - //$object = new token; - //$token = $object->create('login'); + //create token + //$object = new token; + //$token = $object->create('login'); - //add multi-lingual support - $language = new text; - $text = $language->get(null, '/core/authentication'); + //add multi-lingual support + $language = new text; + $text = $language->get(null, '/core/authentication'); - //initialize a template object - $view = new template(); - $view->engine = 'smarty'; - $view->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/authentication/resources/views/'; - $view->cache_dir = sys_get_temp_dir(); - $view->init(); + //initialize a template object + $view = new template(); + $view->engine = 'smarty'; + $view->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/authentication/resources/views/'; + $view->cache_dir = sys_get_temp_dir(); + $view->init(); - //assign default values to the template - $view->assign("project_path", PROJECT_PATH); - $view->assign("login_destination_url", $login_destination); - $view->assign("favicon", $theme_favicon); - $view->assign("login_title", $text['label-username']); - $view->assign("login_username", $text['label-username']); - $view->assign("login_logo_width", $theme_login_logo_width); - $view->assign("login_logo_height", $theme_login_logo_height); - $view->assign("login_logo_source", $theme_logo); - $view->assign("button_login", $text['button-login']); + //assign default values to the template + $view->assign("project_path", PROJECT_PATH); + $view->assign("login_destination_url", $login_destination); + $view->assign("favicon", $theme_favicon); + $view->assign("login_title", $text['label-username']); + $view->assign("login_username", $text['label-username']); + $view->assign("login_logo_width", $theme_login_logo_width); + $view->assign("login_logo_height", $theme_login_logo_height); + $view->assign("login_logo_source", $theme_logo); + $view->assign("button_login", $text['button-login']); + $view->assign("favicon", $theme_favicon); + $view->assign("message_delay", $theme_message_delay); + + //messages + $view->assign('messages', message::html(true, ' ')); + + //show the views + $content = $view->render('username.htm'); + echo $content; + exit; + } + + //show the authentication code view + if (!isset($_POST['authentication_code'])) { + + //get the username + if (!isset($this->username) && isset($_REQUEST['username'])) { + $this->username = $_REQUEST['username']; + $_SESSION['username'] = $this->username; + } + + //get the domain name + if (!empty($_SESSION['username'])) { + $auth = new authentication; + $auth->get_domain(); + $this->domain_uuid = $_SESSION['domain_uuid']; + $this->domain_name = $_SESSION['domain_name']; + $this->username = $_SESSION['username']; + } + + //get the user details + $sql = "select user_uuid, username, user_email, contact_uuid, user_totp_secret\n"; + $sql .= "from v_users\n"; + $sql .= "where (\n"; + $sql .= " username = :username\n"; + $sql .= " or user_email = :username\n"; + $sql .= ")\n"; + if (empty($_SESSION["users"]["unique"]["text"]) || $_SESSION["users"]["unique"]["text"] != "global") { + //unique username per domain (not globally unique across system - example: email address) + $sql .= "and domain_uuid = :domain_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $sql .= "and (user_type = 'default' or user_type is null) "; + $parameters['username'] = $this->username; + $row = $this->database->select($sql, $parameters, 'row'); + if (empty($row) || !is_array($row) || @sizeof($row) == 0) { + //clear submitted usernames + unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); + + //build the result array + $result["plugin"] = "totp"; + $result["domain_uuid"] = $_SESSION["domain_uuid"]; + $result["domain_name"] = $_SESSION["domain_name"]; + $result["authorized"] = false; + + //retun the array + return $result; + } + unset($parameters); + + //set class variables + $this->user_uuid = $row['user_uuid']; + $this->user_email = $row['user_email']; + $this->contact_uuid = $row['contact_uuid']; + $this->user_totp_secret = $row['user_totp_secret']; + + //set a few session variables + $_SESSION["user_uuid"] = $row['user_uuid']; + $_SESSION["username"] = $row['username']; + $_SESSION["user_email"] = $row['user_email']; + $_SESSION["contact_uuid"] = $row["contact_uuid"]; + + //get the domain + $domain_array = explode(":", $_SERVER["HTTP_HOST"]); + $domain_name = $domain_array[0]; + + //create token + //$object = new token; + //$token = $object->create('login'); + + //add multi-lingual support + $language = new text; + $text = $language->get(null, '/core/authentication'); + + //initialize a template object + $view = new template(); + $view->engine = 'smarty'; + $view->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/authentication/resources/views/'; + $view->cache_dir = sys_get_temp_dir(); + $view->init(); + + //assign values to the template + $view->assign("project_path", PROJECT_PATH); + $view->assign("login_destination_url", $login_destination); + $view->assign("favicon", $theme_favicon); + $view->assign("login_title", $text['label-verify']); + $view->assign("login_totp_description", $text['label-totp_description']); + $view->assign("login_authentication_code", $text['label-authentication_code']); + $view->assign("login_logo_width", $theme_login_logo_width); + $view->assign("login_logo_height", $theme_login_logo_height); + $view->assign("login_logo_source", $theme_logo); + $view->assign("favicon", $theme_favicon); + $view->assign("background_video", $theme_background_video); + if (!empty($_SESSION['username'])) { + $view->assign("username", $_SESSION['username']); + $view->assign("button_cancel", $text['button-cancel']); + } + + //show the views + if (!empty($_SESSION['authentication']['plugin']['database']['authorized']) && empty($this->user_totp_secret)) { + + //create the totp secret + $base32 = new base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', false, true, true); + $user_totp_secret = $base32->encode(generate_password(20, 3)); + $this->user_totp_secret = $user_totp_secret; + + //add user setting to array for update + $x = 0; + $array['users'][$x]['user_uuid'] = $this->user_uuid; + $array['users'][$x]['domain_uuid'] = $this->domain_uuid; + $array['users'][$x]['user_totp_secret'] = $this->user_totp_secret; + + //add the user_edit permission + $p = permissions::new(); + $p->add("user_edit", "temp"); + + //save the data + $this->database->save($array); + + //remove the temporary permission + $p->delete("user_edit", "temp"); + + //qr code includes + require_once 'resources/qr_code/QRErrorCorrectLevel.php'; + require_once 'resources/qr_code/QRCode.php'; + require_once 'resources/qr_code/QRCodeImage.php'; + + //build the otp authentication url + $otpauth = "otpauth://totp/" . $this->username; + $otpauth .= "?secret=" . $this->user_totp_secret; + $otpauth .= "&issuer=" . $_SESSION['domain_name']; + + //build the qr code image + try { + $code = new QRCode (-1, QRErrorCorrectLevel::H); + $code->addData($otpauth); + $code->make(); + $img = new QRCodeImage ($code, $width = 210, $height = 210, $quality = 50); + $img->draw(); + $image = $img->getImage(); + $img->finish(); + } catch (Exception $error) { + echo $error; + } + + //assign values to the template + $view->assign("totp_secret", $this->user_totp_secret); + $view->assign("totp_image", base64_encode($image)); + $view->assign("totp_description", $text['description-totp']); + $view->assign("button_next", $text['button-next']); $view->assign("favicon", $theme_favicon); $view->assign("message_delay", $theme_message_delay); //messages $view->assign('messages', message::html(true, ' ')); - //show the views - $content = $view->render('username.htm'); - echo $content; - exit; - } - - //show the authentication code view - if (!isset($_POST['authentication_code'])) { - - //get the username - if (!isset($this->username) && isset($_REQUEST['username'])) { - $this->username = $_REQUEST['username']; - $_SESSION['username'] = $this->username; - } - - //get the domain name - if (!empty($_SESSION['username'])) { - $auth = new authentication; - $auth->get_domain(); - $this->domain_uuid = $_SESSION['domain_uuid']; - $this->domain_name = $_SESSION['domain_name']; - $this->username = $_SESSION['username']; - } - - //get the user details - $sql = "select user_uuid, username, user_email, contact_uuid, user_totp_secret\n"; - $sql .= "from v_users\n"; - $sql .= "where (\n"; - $sql .= " username = :username\n"; - $sql .= " or user_email = :username\n"; - $sql .= ")\n"; - if (empty($_SESSION["users"]["unique"]["text"]) || $_SESSION["users"]["unique"]["text"] != "global") { - //unique username per domain (not globally unique across system - example: email address) - $sql .= "and domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $sql .= "and (user_type = 'default' or user_type is null) "; - $parameters['username'] = $this->username; - $row = $this->database->select($sql, $parameters, 'row'); - if (empty($row) || !is_array($row) || @sizeof($row) == 0) { - //clear submitted usernames - unset($this->username, $_SESSION['username'], $_REQUEST['username'], $_POST['username']); - - //build the result array - $result["plugin"] = "totp"; - $result["domain_uuid"] = $_SESSION["domain_uuid"]; - $result["domain_name"] = $_SESSION["domain_name"]; - $result["authorized"] = false; - - //retun the array - return $result; - } - unset($parameters); - - //set class variables - $this->user_uuid = $row['user_uuid']; - $this->user_email = $row['user_email']; - $this->contact_uuid = $row['contact_uuid']; - $this->user_totp_secret = $row['user_totp_secret']; - - //set a few session variables - $_SESSION["user_uuid"] = $row['user_uuid']; - $_SESSION["username"] = $row['username']; - $_SESSION["user_email"] = $row['user_email']; - $_SESSION["contact_uuid"] = $row["contact_uuid"]; - - //get the domain - $domain_array = explode(":", $_SERVER["HTTP_HOST"]); - $domain_name = $domain_array[0]; - - //create token - //$object = new token; - //$token = $object->create('login'); - - //add multi-lingual support - $language = new text; - $text = $language->get(null, '/core/authentication'); - - //initialize a template object - $view = new template(); - $view->engine = 'smarty'; - $view->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/authentication/resources/views/'; - $view->cache_dir = sys_get_temp_dir(); - $view->init(); - + //render the template + $content = $view->render('totp_secret.htm'); + } else { //assign values to the template - $view->assign("project_path", PROJECT_PATH); - $view->assign("login_destination_url", $login_destination); - $view->assign("favicon", $theme_favicon); - $view->assign("login_title", $text['label-verify']); - $view->assign("login_totp_description", $text['label-totp_description']); - $view->assign("login_authentication_code", $text['label-authentication_code']); - $view->assign("login_logo_width", $theme_login_logo_width); - $view->assign("login_logo_height", $theme_login_logo_height); - $view->assign("login_logo_source", $theme_logo); - $view->assign("favicon", $theme_favicon); - $view->assign("background_video", $theme_background_video); - if (!empty($_SESSION['username'])) { - $view->assign("username", $_SESSION['username']); - $view->assign("button_cancel", $text['button-cancel']); - } + $view->assign("button_verify", $text['label-verify']); + $view->assign("message_delay", $theme_message_delay); - //show the views - if (!empty($_SESSION['authentication']['plugin']['database']['authorized']) && empty($this->user_totp_secret)) { + //messages + $view->assign('messages', message::html(true, ' ')); - //create the totp secret - $base32 = new base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE); - $user_totp_secret = $base32->encode(generate_password(20,3)); - $this->user_totp_secret = $user_totp_secret; - - //add user setting to array for update - $x = 0; - $array['users'][$x]['user_uuid'] = $this->user_uuid; - $array['users'][$x]['domain_uuid'] = $this->domain_uuid; - $array['users'][$x]['user_totp_secret'] = $this->user_totp_secret; - - //add the user_edit permission - $p = permissions::new(); - $p->add("user_edit", "temp"); - - //save the data - $this->database->save($array); - - //remove the temporary permission - $p->delete("user_edit", "temp"); - - //qr code includes - require_once 'resources/qr_code/QRErrorCorrectLevel.php'; - require_once 'resources/qr_code/QRCode.php'; - require_once 'resources/qr_code/QRCodeImage.php'; - - //build the otp authentication url - $otpauth = "otpauth://totp/".$this->username; - $otpauth .= "?secret=".$this->user_totp_secret; - $otpauth .= "&issuer=".$_SESSION['domain_name']; - - //build the qr code image - try { - $code = new QRCode (- 1, QRErrorCorrectLevel::H); - $code->addData($otpauth); - $code->make(); - $img = new QRCodeImage ($code, $width=210, $height=210, $quality=50); - $img->draw(); - $image = $img->getImage(); - $img->finish(); - } - catch (Exception $error) { - echo $error; - } - - //assign values to the template - $view->assign("totp_secret", $this->user_totp_secret); - $view->assign("totp_image", base64_encode($image)); - $view->assign("totp_description", $text['description-totp']); - $view->assign("button_next", $text['button-next']); - $view->assign("favicon", $theme_favicon); - $view->assign("message_delay", $theme_message_delay); - - //messages - $view->assign('messages', message::html(true, ' ')); - - //render the template - $content = $view->render('totp_secret.htm'); - } - else { - //assign values to the template - $view->assign("button_verify", $text['label-verify']); - $view->assign("message_delay", $theme_message_delay); - - //messages - $view->assign('messages', message::html(true, ' ')); - - //render the template - $content = $view->render('totp.htm'); - } - echo $content; - exit; + //render the template + $content = $view->render('totp.htm'); } + echo $content; + exit; + } //if authorized then verify - if (isset($_POST['authentication_code'])) { + if (isset($_POST['authentication_code'])) { - //get the user details - $sql = "select user_uuid, user_email, contact_uuid, user_totp_secret\n"; - $sql .= "from v_users\n"; - $sql .= "where (\n"; - $sql .= " username = :username\n"; - $sql .= " or user_email = :username\n"; - $sql .= ")\n"; + //get the user details + $sql = "select user_uuid, user_email, contact_uuid, user_totp_secret\n"; + $sql .= "from v_users\n"; + $sql .= "where (\n"; + $sql .= " username = :username\n"; + $sql .= " or user_email = :username\n"; + $sql .= ")\n"; + if ($users_unique != "global") { + //unique username per domain (not globally unique across system - example: email address) + $sql .= "and domain_uuid = :domain_uuid "; + $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; + } + $parameters['username'] = $_SESSION["username"]; + $row = $this->database->select($sql, $parameters, 'row'); + $this->user_uuid = $row['user_uuid']; + $this->user_email = $row['user_email']; + $this->contact_uuid = $row['contact_uuid']; + $this->user_totp_secret = $row['user_totp_secret']; + unset($parameters); + + //create the authenticator object + $totp = new google_authenticator; + + //validate the code + if ($totp->checkCode($this->user_totp_secret, $_POST['authentication_code'])) { + $auth_valid = true; + } else { + $auth_valid = false; + } + + //clear posted authentication code + unset($_POST['authentication_code']); + + //check if contacts app exists + $contacts_exists = file_exists($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/core/contacts/') ? true : false; + + //get the user details + if ($auth_valid) { + //get user data from the database + $sql = "select "; + $sql .= " u.user_uuid, "; + $sql .= " u.username, "; + $sql .= " u.user_email, "; + $sql .= " u.contact_uuid "; + if ($contacts_exists) { + $sql .= ","; + $sql .= "c.contact_organization, "; + $sql .= "c.contact_name_given, "; + $sql .= "c.contact_name_family, "; + $sql .= "a.contact_attachment_uuid "; + } + $sql .= "from "; + $sql .= " v_users as u "; + if ($contacts_exists) { + $sql .= "left join v_contacts as c on u.contact_uuid = c.contact_uuid and u.contact_uuid is not null "; + $sql .= "left join v_contact_attachments as a on u.contact_uuid = a.contact_uuid and u.contact_uuid is not null and a.attachment_primary = true and a.attachment_filename is not null and a.attachment_content is not null "; + } + $sql .= "where "; + $sql .= " u.user_uuid = :user_uuid "; if ($users_unique != "global") { //unique username per domain (not globally unique across system - example: email address) - $sql .= "and domain_uuid = :domain_uuid "; + $sql .= "and u.domain_uuid = :domain_uuid "; $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; } - $parameters['username'] = $_SESSION["username"]; - $row = $this->database->select($sql, $parameters, 'row'); - $this->user_uuid = $row['user_uuid']; - $this->user_email = $row['user_email']; - $this->contact_uuid = $row['contact_uuid']; - $this->user_totp_secret = $row['user_totp_secret']; + $parameters['user_uuid'] = $_SESSION["user_uuid"]; + $row = $this->database->select($sql, $parameters, 'row'); unset($parameters); - - //create the authenticator object - $totp = new google_authenticator; - - //validate the code - if ($totp->checkCode($this->user_totp_secret, $_POST['authentication_code'])) { - $auth_valid = true; - } - else { - $auth_valid = false; - } - - //clear posted authentication code - unset($_POST['authentication_code']); - - //check if contacts app exists - $contacts_exists = file_exists($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/contacts/') ? true : false; - - //get the user details - if ($auth_valid) { - //get user data from the database - $sql = "select "; - $sql .= " u.user_uuid, "; - $sql .= " u.username, "; - $sql .= " u.user_email, "; - $sql .= " u.contact_uuid "; - if ($contacts_exists) { - $sql .= ","; - $sql .= "c.contact_organization, "; - $sql .= "c.contact_name_given, "; - $sql .= "c.contact_name_family, "; - $sql .= "a.contact_attachment_uuid "; - } - $sql .= "from "; - $sql .= " v_users as u "; - if ($contacts_exists) { - $sql .= "left join v_contacts as c on u.contact_uuid = c.contact_uuid and u.contact_uuid is not null "; - $sql .= "left join v_contact_attachments as a on u.contact_uuid = a.contact_uuid and u.contact_uuid is not null and a.attachment_primary = true and a.attachment_filename is not null and a.attachment_content is not null "; - } - $sql .= "where "; - $sql .= " u.user_uuid = :user_uuid "; - if ($users_unique != "global") { - //unique username per domain (not globally unique across system - example: email address) - $sql .= "and u.domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $_SESSION["domain_uuid"]; - } - $parameters['user_uuid'] = $_SESSION["user_uuid"]; - $row = $this->database->select($sql, $parameters, 'row'); - unset($parameters); - } - else { + } else { // //destroy session // session_unset(); // session_destroy(); @@ -397,64 +394,64 @@ class plugin_totp { // //exit the code // exit(); - //clear authentication session - unset($_SESSION['authentication']); + //clear authentication session + unset($_SESSION['authentication']); - // clear username - unset($_SESSION["username"]); - } - - /* - //check if user successfully logged in during the interval - //$sql = "select user_log_uuid, timestamp, user_name, user_agent, remote_address "; - $sql = "select count(*) as count "; - $sql .= "from v_user_logs "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and user_uuid = :user_uuid "; - $sql .= "and user_agent = :user_agent "; - $sql .= "and type = 'login' "; - $sql .= "and result = 'success' "; - $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) > 3 "; - $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) < 300 "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['user_uuid'] = $this->user_uuid; - $parameters['user_agent'] = $_SERVER['HTTP_USER_AGENT']; - $user_log_count = $this->database->select($sql, $parameters, 'all'); - //view_array($user_log_count); - unset($sql, $parameters); - */ - - //build the result array - $result["plugin"] = "totp"; - $result["domain_name"] = $_SESSION["domain_name"]; - $result["username"] = $_SESSION["username"] ?? null; - $result["user_uuid"] = $_SESSION["user_uuid"]; - $result["domain_uuid"] = $_SESSION["domain_uuid"]; - $result["contact_uuid"] = $_SESSION["contact_uuid"]; - if ($contacts_exists) { - $result["contact_organization"] = $row["contact_organization"]; - $result["contact_name_given"] = $row["contact_name_given"]; - $result["contact_name_family"] = $row["contact_name_family"]; - $result["contact_image"] = $row["contact_attachment_uuid"]; - } - $result["authorized"] = $auth_valid ? true : false; - - //add the failed login to user logs - if (!$auth_valid) { - user_logs::add($result); - } - - //retun the array - return $result; - - //$_SESSION['authentication']['plugin']['totp']['plugin'] = "totp"; - //$_SESSION['authentication']['plugin']['totp']['domain_name'] = $_SESSION["domain_name"]; - //$_SESSION['authentication']['plugin']['totp']['username'] = $row['username']; - //$_SESSION['authentication']['plugin']['totp']['user_uuid'] = $_SESSION["user_uuid"]; - //$_SESSION['authentication']['plugin']['totp']['contact_uuid'] = $_SESSION["contact_uuid"]; - //$_SESSION['authentication']['plugin']['totp']['domain_uuid'] = $_SESSION["domain_uuid"]; - //$_SESSION['authentication']['plugin']['totp']['authorized'] = $auth_valid ? true : false; + // clear username + unset($_SESSION["username"]); } + /* + //check if user successfully logged in during the interval + //$sql = "select user_log_uuid, timestamp, user_name, user_agent, remote_address "; + $sql = "select count(*) as count "; + $sql .= "from v_user_logs "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and user_uuid = :user_uuid "; + $sql .= "and user_agent = :user_agent "; + $sql .= "and type = 'login' "; + $sql .= "and result = 'success' "; + $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) > 3 "; + $sql .= "and floor(extract(epoch from now()) - extract(epoch from timestamp)) < 300 "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['user_uuid'] = $this->user_uuid; + $parameters['user_agent'] = $_SERVER['HTTP_USER_AGENT']; + $user_log_count = $this->database->select($sql, $parameters, 'all'); + //view_array($user_log_count); + unset($sql, $parameters); + */ + + //build the result array + $result["plugin"] = "totp"; + $result["domain_name"] = $_SESSION["domain_name"]; + $result["username"] = $_SESSION["username"] ?? null; + $result["user_uuid"] = $_SESSION["user_uuid"]; + $result["domain_uuid"] = $_SESSION["domain_uuid"]; + $result["contact_uuid"] = $_SESSION["contact_uuid"]; + if ($contacts_exists) { + $result["contact_organization"] = $row["contact_organization"]; + $result["contact_name_given"] = $row["contact_name_given"]; + $result["contact_name_family"] = $row["contact_name_family"]; + $result["contact_image"] = $row["contact_attachment_uuid"]; + } + $result["authorized"] = $auth_valid ? true : false; + + //add the failed login to user logs + if (!$auth_valid) { + user_logs::add($result); + } + + //retun the array + return $result; + + //$_SESSION['authentication']['plugin']['totp']['plugin'] = "totp"; + //$_SESSION['authentication']['plugin']['totp']['domain_name'] = $_SESSION["domain_name"]; + //$_SESSION['authentication']['plugin']['totp']['username'] = $row['username']; + //$_SESSION['authentication']['plugin']['totp']['user_uuid'] = $_SESSION["user_uuid"]; + //$_SESSION['authentication']['plugin']['totp']['contact_uuid'] = $_SESSION["contact_uuid"]; + //$_SESSION['authentication']['plugin']['totp']['domain_uuid'] = $_SESSION["domain_uuid"]; + //$_SESSION['authentication']['plugin']['totp']['authorized'] = $auth_valid ? true : false; + } + } } diff --git a/core/contacts/contact_import.php b/core/contacts/contact_import.php index c9e9d7cb9d..22f668d22f 100644 --- a/core/contacts/contact_import.php +++ b/core/contacts/contact_import.php @@ -38,18 +38,6 @@ $language = new text; $text = $language->get(); -//built in str_getcsv requires PHP 5.3 or higher, this function can be used to reproduct the functionality but requirs PHP 5.1.0 or higher - if (!function_exists('str_getcsv')) { - function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { - $fp = fopen("php://memory", 'r+'); - fputs($fp, $input); - rewind($fp); - $data = fgetcsv($fp, null, $delimiter, $enclosure); // $escape only got added in 5.3.0 - fclose($fp); - return $data; - } - } - //set the max php execution time ini_set('max_execution_time', 7200); @@ -252,6 +240,14 @@ } //get the parent table + /** + * Retrieves the parent table name from a given schema based on the provided table name. + * + * @param array $schema A list of tables and their properties in the database schema. + * @param string $table_name The name of the table for which to retrieve the parent. + * + * @return string|null The parent table name, or null if no match is found. + */ function get_parent($schema,$table_name) { foreach ($schema as $row) { if ($row['table'] == $table_name) { diff --git a/core/contacts/contact_import_google.php b/core/contacts/contact_import_google.php index 90cf218237..8ae880aae8 100644 --- a/core/contacts/contact_import_google.php +++ b/core/contacts/contact_import_google.php @@ -581,6 +581,13 @@ require_once "resources/footer.php"; // used above +/** + * Retrieves the contents of a URL using cURL. + * + * @param string $url The URL to retrieve. + * + * @return string The contents of the retrieved URL, or FALSE if an error occurred. + */ function curl_file_get_contents($url) { $curl = curl_init(); $userAgent = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)'; diff --git a/core/contacts/resources/classes/contacts.php b/core/contacts/resources/classes/contacts.php index 1a37be4095..d77b5ad735 100644 --- a/core/contacts/resources/classes/contacts.php +++ b/core/contacts/resources/classes/contacts.php @@ -25,262 +25,304 @@ */ //define the contacts class - class contacts { +class contacts { - /** - * declare constant variables - */ - const app_name = 'contacts'; - const app_uuid = '04481e0e-a478-c559-adad-52bd4174574c'; + /** + * declare constant variables + */ + const app_name = 'contacts'; + const app_uuid = '04481e0e-a478-c559-adad-52bd4174574c'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $tables; - private $table; - private $uuid_prefix; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $tables; + private $table; + private $uuid_prefix; - /** - * declare public variables - */ - public $contact_uuid; + /** + * declare public variables + */ + public $contact_uuid; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //assign private variables - $this->permission_prefix = 'contact_'; - $this->list_page = 'contacts.php'; - $this->tables[] = 'contact_addresses'; - $this->tables[] = 'contact_attachments'; - $this->tables[] = 'contact_emails'; - $this->tables[] = 'contact_groups'; - $this->tables[] = 'contact_notes'; - $this->tables[] = 'contact_phones'; - $this->tables[] = 'contact_relations'; - $this->tables[] = 'contact_settings'; - $this->tables[] = 'contact_times'; - $this->tables[] = 'contact_urls'; - $this->tables[] = 'contact_users'; - $this->tables[] = 'contacts'; - $this->uuid_prefix = 'contact_'; - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + //assign private variables + $this->permission_prefix = 'contact_'; + $this->list_page = 'contacts.php'; + $this->tables[] = 'contact_addresses'; + $this->tables[] = 'contact_attachments'; + $this->tables[] = 'contact_emails'; + $this->tables[] = 'contact_groups'; + $this->tables[] = 'contact_notes'; + $this->tables[] = 'contact_phones'; + $this->tables[] = 'contact_relations'; + $this->tables[] = 'contact_settings'; + $this->tables[] = 'contact_times'; + $this->tables[] = 'contact_urls'; + $this->tables[] = 'contact_users'; + $this->tables[] = 'contacts'; + $this->uuid_prefix = 'contact_'; + } - //add multi-lingual support - $language = new text; - $text = $language->get(); + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - if (is_array($this->tables) && @sizeof($this->tables) != 0) { - foreach ($this->tables as $table) { - $array[$table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$table][$x]['domain_uuid'] = $this->domain_uuid; - } - } - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temp permissions - $p = permissions::new(); - foreach ($this->tables as $table) { - $p->add(database::singular($table).'_delete', 'temp'); - } - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temp permissions - foreach ($this->tables as $table) { - $p->delete(database::singular($table).'_delete', 'temp'); - } - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - public function delete_properties($records) { //add multi-lingual support - $language = new text; - $text = $language->get(); + $language = new text; + $text = $language->get(); //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + if (is_array($records) && @sizeof($records) != 0) { - //check permissions and build the delete array - $x = 0; - foreach ($records as $property_name => $properties) { - if (permission_exists(database::singular($property_name).'_delete')) { - if (is_array($properties) && @sizeof($properties) != 0) { - foreach ($properties as $property) { - if ($property['checked'] == 'true' && is_uuid($property['uuid'])) { - $array[$property_name][$x][database::singular($property_name).'_uuid'] = $property['uuid']; - $array[$property_name][$x]['contact_uuid'] = $this->contact_uuid; - $array[$property_name][$x]['domain_uuid'] = $this->domain_uuid; - $x++; - } - } - } + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + if (is_array($this->tables) && @sizeof($this->tables) != 0) { + foreach ($this->tables as $table) { + $array[$table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$table][$x]['domain_uuid'] = $this->domain_uuid; } } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - } - unset($records); + } } - } - public function delete_users($records) { - //assign private variables - $this->permission_prefix = 'contact_user_'; - $this->table = 'contact_users'; - $this->uuid_prefix = 'contact_user_'; + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //grant temp permissions + $p = permissions::new(); + foreach ($this->tables as $table) { + $p->add(database::singular($table) . '_delete', 'temp'); } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //execute delete + $this->database->delete($array); + unset($array); - //filter out unchecked ivr menu options, build delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['contact_uuid'] = $this->contact_uuid; - $x++; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - } - unset($records); + //revoke temp permissions + foreach ($this->tables as $table) { + $p->delete(database::singular($table) . '_delete', 'temp'); } + + //set message + message::add($text['message-delete']); + } + unset($records); } } + } - public function delete_groups($records) { - //assign private variables - $this->permission_prefix = 'contact_group_'; - $this->table = 'contact_groups'; - $this->uuid_prefix = 'contact_group_'; + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete_properties($records) { + //add multi-lingual support + $language = new text; + $text = $language->get(); - if (permission_exists($this->permission_prefix.'delete')) { + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } - //add multi-lingual support - $language = new text; - $text = $language->get(); + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked ivr menu options, build delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['contact_uuid'] = $this->contact_uuid; - $x++; - } + //check permissions and build the delete array + $x = 0; + foreach ($records as $property_name => $properties) { + if (permission_exists(database::singular($property_name) . '_delete')) { + if (is_array($properties) && @sizeof($properties) != 0) { + foreach ($properties as $property) { + if ($property['checked'] == 'true' && is_uuid($property['uuid'])) { + $array[$property_name][$x][database::singular($property_name) . '_uuid'] = $property['uuid']; + $array[$property_name][$x]['contact_uuid'] = $this->contact_uuid; + $array[$property_name][$x]['domain_uuid'] = $this->domain_uuid; + $x++; } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - } - unset($records); + } } + } } - } //method - } //class + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + } + unset($records); + } + } + + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete_users($records) { + //assign private variables + $this->permission_prefix = 'contact_user_'; + $this->table = 'contact_users'; + $this->uuid_prefix = 'contact_user_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked ivr menu options, build delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['contact_uuid'] = $this->contact_uuid; + $x++; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + } + unset($records); + } + } + } + + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete_groups($records) { + //assign private variables + $this->permission_prefix = 'contact_group_'; + $this->table = 'contact_groups'; + $this->uuid_prefix = 'contact_group_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked ivr menu options, build delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['contact_uuid'] = $this->contact_uuid; + $x++; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + } + unset($records); + } + } + } //method + +} //class diff --git a/core/dashboard/resources/classes/dashboard.php b/core/dashboard/resources/classes/dashboard.php index 96cffed905..0b62a5962c 100644 --- a/core/dashboard/resources/classes/dashboard.php +++ b/core/dashboard/resources/classes/dashboard.php @@ -27,585 +27,640 @@ /** * dashboard class */ - class dashboard { +class dashboard { - /** - * declare constant variables - */ - const app_name = 'dashboard'; - const app_uuid = '55533bef-4f04-434a-92af-999c1e9927f7'; + /** + * declare constant variables + */ + const app_name = 'dashboard'; + const app_uuid = '55533bef-4f04-434a-92af-999c1e9927f7'; - /** - * declare the variables - */ - private $database; - private $name; - private $table; - private $tables; - private $toggle_field; - private $toggle_values; - private $description_field; - private $location; - private $uuid_prefix; + /** + * declare the variables + */ + private $database; + private $name; + private $table; + private $tables; + private $toggle_field; + private $toggle_values; + private $description_field; + private $location; + private $uuid_prefix; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set objects - $this->database = $setting_array['database'] ?? database::new(); + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign the variables - $this->tables[] = 'dashboards'; - $this->tables[] = 'dashboard_widgets'; - $this->tables[] = 'dashboard_widget_groups'; - $this->toggle_field = 'dashboard_enabled'; - $this->toggle_values = ['true','false']; - $this->description_field = 'dashboard_description'; - $this->location = 'dashboard.php'; - $this->uuid_prefix = 'dashboard_'; - } + //assign the variables + $this->tables[] = 'dashboards'; + $this->tables[] = 'dashboard_widgets'; + $this->tables[] = 'dashboard_widget_groups'; + $this->toggle_field = 'dashboard_enabled'; + $this->toggle_values = ['true', 'false']; + $this->description_field = 'dashboard_description'; + $this->location = 'dashboard.php'; + $this->uuid_prefix = 'dashboard_'; + } - /** - * delete rows from the database - */ - public function delete($records) { - //assign the variables - $this->name = 'dashboard'; - $this->table = 'dashboards'; + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + //assign the variables + $this->name = 'dashboard'; + $this->table = 'dashboards'; - if (permission_exists($this->name.'_delete')) { + if (permission_exists($this->name . '_delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_uuid'])) { + if (is_array($this->tables) && @sizeof($this->tables) != 0) { + foreach ($this->tables as $table) { + $array[$table][$x][$this->uuid_prefix . 'uuid'] = $record['dashboard_uuid']; + } + } + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temp permissions + $p = permissions::new(); + foreach ($this->tables as $table) { + $p->add(database::singular($table) . '_delete', 'temp'); } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //execute delete + $this->database->delete($array); + unset($array); - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_uuid'])) { - if (is_array($this->tables) && @sizeof($this->tables) != 0) { - foreach ($this->tables as $table) { - $array[$table][$x][$this->uuid_prefix.'uuid'] = $record['dashboard_uuid']; + //revoke temp permissions + foreach ($this->tables as $table) { + $p->delete(database::singular($table) . '_delete', 'temp'); + } + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + //assign the variables + $this->name = 'dashboard'; + $this->table = 'dashboards'; + + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (isset($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_uuid'])) { + $uuids[] = "'" . $record['dashboard_uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + //assign the variables + $this->name = 'dashboard'; + $this->table = 'dashboards'; + + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_uuid'])) { + $uuids[] = "'" . $record['dashboard_uuid'] . "'"; + } + } + + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + foreach ($uuids as $uuid) { + $dashboard_uuid = uuid(); + $widget_uuids = []; + + foreach ($this->tables as $table) { + $sql = "select * from v_" . $table . " "; + $sql .= "where dashboard_uuid = " . $uuid . " "; + $database = new database; + $rows = $database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $x = 0; + foreach ($rows as $row) { + //skip child widgets + if (!empty($row['dashboard_widget_parent_uuid'])) { + continue; + } + + //prevent copying these fields + unset($row['insert_date'], $row['insert_user']); + unset($row['update_date'], $row['update_user']); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; } } - } - } - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { + //copy data + $array[$table][$x] = $row; - //grant temp permissions - $p = permissions::new(); - foreach ($this->tables as $table) { - $p->add(database::singular($table).'_delete', 'temp'); + //add copy to the description + $array[$table][$x]['dashboard_uuid'] = $dashboard_uuid; + if ($table === $this->table) { + $array[$table][$x][$this->description_field] = trim($row[$this->description_field]) . ' (' . $text['label-copy'] . ')'; } - //execute delete - $this->database->delete($array); - unset($array); + //handle widget uuid + if (isset($row['dashboard_widget_uuid']) && !isset($row['dashboard_widget_group_uuid'])) { + $widget_uuid = uuid(); + $widget_uuids[$array[$table][$x]['dashboard_widget_uuid']] = $widget_uuid; + $array[$table][$x]['dashboard_widget_uuid'] = $widget_uuid; + //add child widgets under parent widget + if ($row['widget_path'] === 'dashboard/parent') { + $x++; + foreach ($rows as $child) { + if ($child['dashboard_widget_parent_uuid'] == $row['dashboard_widget_uuid']) { + unset($child['insert_date'], $child['insert_user']); + unset($child['update_date'], $child['update_user']); - //revoke temp permissions - foreach ($this->tables as $table) { - $p->delete(database::singular($table).'_delete', 'temp'); - } - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle a field between two values - */ - public function toggle($records) { - //assign the variables - $this->name = 'dashboard'; - $this->table = 'dashboards'; - - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if (isset($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_uuid'])) { - $uuids[] = "'".$record['dashboard_uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - //assign the variables - $this->name = 'dashboard'; - $this->table = 'dashboards'; - - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_uuid'])) { - $uuids[] = "'".$record['dashboard_uuid']."'"; - } - } - - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - foreach ($uuids as $uuid) { - $dashboard_uuid = uuid(); - $widget_uuids = []; - - foreach ($this->tables as $table) { - $sql = "select * from v_".$table." "; - $sql .= "where dashboard_uuid = ".$uuid." "; - $database = new database; - $rows = $database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $x = 0; - foreach ($rows as $row) { - //skip child widgets - if (!empty($row['dashboard_widget_parent_uuid'])) { - continue; - } - - //prevent copying these fields - unset($row['insert_date'], $row['insert_user']); - unset($row['update_date'], $row['update_user']); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$table][$x] = $row; - - //add copy to the description + $array[$table][$x] = $child; $array[$table][$x]['dashboard_uuid'] = $dashboard_uuid; - if ($table === $this->table) { - $array[$table][$x][$this->description_field] = trim($row[$this->description_field]).' ('.$text['label-copy'].')'; - } - //handle widget uuid - if (isset($row['dashboard_widget_uuid']) && !isset($row['dashboard_widget_group_uuid'])) { - $widget_uuid = uuid(); - $widget_uuids[$array[$table][$x]['dashboard_widget_uuid']] = $widget_uuid; - $array[$table][$x]['dashboard_widget_uuid'] = $widget_uuid; - //add child widgets under parent widget - if ($row['widget_path'] === 'dashboard/parent') { - $x++; - foreach ($rows as $child) { - if ($child['dashboard_widget_parent_uuid'] == $row['dashboard_widget_uuid']) { - unset($child['insert_date'], $child['insert_user']); - unset($child['update_date'], $child['update_user']); - - $array[$table][$x] = $child; - $array[$table][$x]['dashboard_uuid'] = $dashboard_uuid; - - $child_uuid = uuid(); - $widget_uuids[$array[$table][$x]['dashboard_widget_uuid']] = $child_uuid; - $array[$table][$x]['dashboard_widget_uuid'] = $child_uuid; - $array[$table][$x]['dashboard_widget_parent_uuid'] = $widget_uuids[$array[$table][$x]['dashboard_widget_parent_uuid']] ?? ''; - } - $x++; - } - } - } - - //handle widget group uuid - if (isset($row['dashboard_widget_group_uuid'])) { - $array[$table][$x]['dashboard_widget_group_uuid'] = uuid(); - $array[$table][$x]['dashboard_widget_uuid'] = $widget_uuids[$array[$table][$x]['dashboard_widget_uuid']]; - } - - //increment the id - $x++; + $child_uuid = uuid(); + $widget_uuids[$array[$table][$x]['dashboard_widget_uuid']] = $child_uuid; + $array[$table][$x]['dashboard_widget_uuid'] = $child_uuid; + $array[$table][$x]['dashboard_widget_parent_uuid'] = $widget_uuids[$array[$table][$x]['dashboard_widget_parent_uuid']] ?? ''; + } + $x++; } } } + + //handle widget group uuid + if (isset($row['dashboard_widget_group_uuid'])) { + $array[$table][$x]['dashboard_widget_group_uuid'] = uuid(); + $array[$table][$x]['dashboard_widget_uuid'] = $widget_uuids[$array[$table][$x]['dashboard_widget_uuid']]; + } + + //increment the id + $x++; } - unset($sql, $parameters, $rows, $row); } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - //save the array - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); + } } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + //save the array + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); } } - - public function delete_widgets($records) { - //assign the variables - $this->name = 'dashboard_widget'; - $this->table = 'dashboard_widgets'; - - //permission not found return false - if (!permission_exists($this->name.'_delete')) { - return false; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { - $array[$this->table][$x]['dashboard_widget_uuid'] = $record['dashboard_widget_uuid']; - $array[$this->name.'_groups'][$x]['dashboard_widget_uuid'] = $record['dashboard_widget_uuid']; - } - - //increment the id - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - - public function toggle_widgets($records) { - //assign the variables - $this->name = 'dashboard_widget'; - $this->table = 'dashboard_widgets'; - $this->toggle_field = 'widget_enabled'; - - //permission not found return false - if (!permission_exists($this->name.'_edit')) { - return false; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if (isset($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { - $uuids[] = "'".$record['dashboard_widget_uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - - public function assign_widgets($records, $dashboard_uuid, $group_uuid) { - //assign the variables - $this->name = 'dashboard_widget'; - $this->table = 'dashboard_widgets'; - - //permission not found return false - if (!permission_exists($this->name.'_add')) { - return false; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //assign multiple records - if (is_array($records) && @sizeof($records) != 0 && !empty($group_uuid)) { - - //define the group_name and group_uuid - if (!empty($records) && @sizeof($records) != 0) { - $sql = "select group_name, group_uuid from v_groups "; - $sql .= "where group_uuid = :group_uuid "; - $parameters['group_uuid'] = $group_uuid; - $group = $this->database->select($sql, $parameters, 'row'); - } - - //build the delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { - //build array - $uuids[] = "'".$record['dashboard_widget_uuid']."'"; - //assign dashboard widget groups - $array[$this->name.'_groups'][$x][$this->name.'_group_uuid'] = uuid(); - $array[$this->name.'_groups'][$x]['dashboard_uuid'] = $dashboard_uuid; - $array[$this->name.'_groups'][$x][$this->name.'_uuid'] = $record['dashboard_widget_uuid']; - $array[$this->name.'_groups'][$x]['group_uuid'] = $group['group_uuid']; - //increment - $x++; - } - } - - unset($records); - - //exlude exist rows - if (!empty($array) && @sizeof($array) != 0) { - $sql = "select dashboard_uuid, ".$this->name."_uuid, "; - $sql .= "group_uuid from v_".$this->name."_groups "; - $dashboard_widget_groups = $this->database->select($sql, null, 'all'); - $array[$this->name.'_groups'] = array_filter($array[$this->name.'_groups'], function($ar) use ($dashboard_widget_groups) { - foreach ($dashboard_widget_groups as $existing_array_item) { - if ($ar['dashboard_uuid'] == $existing_array_item['dashboard_uuid'] && $ar[$this->name.'_uuid'] == $existing_array_item[$this->name.'_uuid'] && $ar['group_uuid'] == $existing_array_item['group_uuid']) { - return false; - } - } - return true; - }); - unset($dashboard_widget_groups); - } - - //add the checked rows from group - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //execute save - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-add']); - } - } - } - - public function unassign_widgets($records, $dashboard_uuid, $group_uuid) { - //assign the variables - $this->name = 'dashboard_widget'; - $this->table = 'dashboard_widgets'; - - //permission not found return now - if (!permission_exists($this->name.'_add')) { - return false; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //assign multiple records - if (is_array($records) && @sizeof($records) != 0 && !empty($group_uuid)) { - - //define the group_name and group_uuid - if (!empty($records) && @sizeof($records) != 0) { - $sql = "select group_name, group_uuid from v_groups "; - $sql .= "where group_uuid = :group_uuid "; - $parameters['group_uuid'] = $group_uuid; - $group = $this->database->select($sql, $parameters, 'row'); - } - - //build the delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { - //build array - $uuids[] = "'".$record['dashboard_widget_uuid']."'"; - //assign dashboard widget groups - $array[$this->name.'_groups'][$x]['dashboard_uuid'] = $dashboard_uuid; - $array[$this->name.'_groups'][$x][$this->name.'_uuid'] = $record['dashboard_widget_uuid']; - $array[$this->name.'_groups'][$x]['group_uuid'] = $group['group_uuid']; - //increment - $x++; - } - } - - unset($records); - - //include child dashboard widgets and their dasboard_uuid too - if (!empty($uuids) && @sizeof($uuids) != 0) { - $sql = "select dashboard_uuid, ".$this->name."_uuid from v_".$this->table." "; - $sql .= "where ".$this->name."_parent_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, null, 'all'); - if (!empty($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - //assign dashboard widget groups - $array[$this->name.'_groups'][$x]['dashboard_uuid'] = $row['dashboard_uuid']; - $array[$this->name.'_groups'][$x][$this->name.'_uuid'] = $row['dashboard_widget_uuid']; - $array[$this->name.'_groups'][$x]['group_uuid'] = $group['group_uuid']; - //increment - $x++; - } - } - } - - unset($uuids); - - //add the checked rows from group - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //grant temporary permissions - $p = new permissions; - $p->add('dashboard_widget_group_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('dashboard_widget_group_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - } - } - } + + /** + * Delete one or multiple dashboard widgets. + * + * This method deletes the specified dashboard widgets based on their UUIDs and user permissions. + * + * @param array $records An array of records to delete, where each record contains a 'dashboard_widget_uuid' key. + */ + public function delete_widgets($records) { + //assign the variables + $this->name = 'dashboard_widget'; + $this->table = 'dashboard_widgets'; + + //permission not found return false + if (!permission_exists($this->name . '_delete')) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { + $array[$this->table][$x]['dashboard_widget_uuid'] = $record['dashboard_widget_uuid']; + $array[$this->name . '_groups'][$x]['dashboard_widget_uuid'] = $record['dashboard_widget_uuid']; + } + + //increment the id + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + + /** + * Toggle the enabled state of dashboard widgets. + * + * This method updates the database with new toggle states for the specified records. + * + * @param array $records An array of records to update. + */ + public function toggle_widgets($records) { + //assign the variables + $this->name = 'dashboard_widget'; + $this->table = 'dashboard_widgets'; + $this->toggle_field = 'widget_enabled'; + + //permission not found return false + if (!permission_exists($this->name . '_edit')) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (isset($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { + $uuids[] = "'" . $record['dashboard_widget_uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + + /** + * Assign dashboard widgets. + * + * This method assigns multiple records to a group in the database. + * + * @param array $records The list of dashboard widget records to assign. + * @param string $dashboard_uuid The UUID of the dashboard. + * @param string $group_uuid The UUID of the group. + */ + public function assign_widgets($records, $dashboard_uuid, $group_uuid) { + //assign the variables + $this->name = 'dashboard_widget'; + $this->table = 'dashboard_widgets'; + + //permission not found return false + if (!permission_exists($this->name . '_add')) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //assign multiple records + if (is_array($records) && @sizeof($records) != 0 && !empty($group_uuid)) { + + //define the group_name and group_uuid + if (!empty($records) && @sizeof($records) != 0) { + $sql = "select group_name, group_uuid from v_groups "; + $sql .= "where group_uuid = :group_uuid "; + $parameters['group_uuid'] = $group_uuid; + $group = $this->database->select($sql, $parameters, 'row'); + } + + //build the delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { + //build array + $uuids[] = "'" . $record['dashboard_widget_uuid'] . "'"; + //assign dashboard widget groups + $array[$this->name . '_groups'][$x][$this->name . '_group_uuid'] = uuid(); + $array[$this->name . '_groups'][$x]['dashboard_uuid'] = $dashboard_uuid; + $array[$this->name . '_groups'][$x][$this->name . '_uuid'] = $record['dashboard_widget_uuid']; + $array[$this->name . '_groups'][$x]['group_uuid'] = $group['group_uuid']; + //increment + $x++; + } + } + + unset($records); + + //exlude exist rows + if (!empty($array) && @sizeof($array) != 0) { + $sql = "select dashboard_uuid, " . $this->name . "_uuid, "; + $sql .= "group_uuid from v_" . $this->name . "_groups "; + $dashboard_widget_groups = $this->database->select($sql, null, 'all'); + $array[$this->name . '_groups'] = array_filter($array[$this->name . '_groups'], function ($ar) use ($dashboard_widget_groups) { + foreach ($dashboard_widget_groups as $existing_array_item) { + if ($ar['dashboard_uuid'] == $existing_array_item['dashboard_uuid'] && $ar[$this->name . '_uuid'] == $existing_array_item[$this->name . '_uuid'] && $ar['group_uuid'] == $existing_array_item['group_uuid']) { + return false; + } + } + return true; + }); + unset($dashboard_widget_groups); + } + + //add the checked rows from group + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //execute save + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-add']); + } + } + } + + /** + * Unassign widgets from a dashboard. + * + * This method removes the specified widgets from the dashboard and its groups. + * + * @param array $records An array of records to unassign, where each record contains + * the 'dashboard_widget_uuid' key. + * @param string $dashboard_uuid The UUID of the dashboard from which to unassign the widgets. + * @param string $group_uuid The UUID of the group from which to unassign the widgets. + */ + public function unassign_widgets($records, $dashboard_uuid, $group_uuid) { + //assign the variables + $this->name = 'dashboard_widget'; + $this->table = 'dashboard_widgets'; + + //permission not found return now + if (!permission_exists($this->name . '_add')) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/core/dashboard/dashboard_widget_list.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //assign multiple records + if (is_array($records) && @sizeof($records) != 0 && !empty($group_uuid)) { + + //define the group_name and group_uuid + if (!empty($records) && @sizeof($records) != 0) { + $sql = "select group_name, group_uuid from v_groups "; + $sql .= "where group_uuid = :group_uuid "; + $parameters['group_uuid'] = $group_uuid; + $group = $this->database->select($sql, $parameters, 'row'); + } + + //build the delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['dashboard_widget_uuid'])) { + //build array + $uuids[] = "'" . $record['dashboard_widget_uuid'] . "'"; + //assign dashboard widget groups + $array[$this->name . '_groups'][$x]['dashboard_uuid'] = $dashboard_uuid; + $array[$this->name . '_groups'][$x][$this->name . '_uuid'] = $record['dashboard_widget_uuid']; + $array[$this->name . '_groups'][$x]['group_uuid'] = $group['group_uuid']; + //increment + $x++; + } + } + + unset($records); + + //include child dashboard widgets and their dasboard_uuid too + if (!empty($uuids) && @sizeof($uuids) != 0) { + $sql = "select dashboard_uuid, " . $this->name . "_uuid from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_parent_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (!empty($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + //assign dashboard widget groups + $array[$this->name . '_groups'][$x]['dashboard_uuid'] = $row['dashboard_uuid']; + $array[$this->name . '_groups'][$x][$this->name . '_uuid'] = $row['dashboard_widget_uuid']; + $array[$this->name . '_groups'][$x]['group_uuid'] = $group['group_uuid']; + //increment + $x++; + } + } + } + + unset($uuids); + + //add the checked rows from group + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //grant temporary permissions + $p = new permissions; + $p->add('dashboard_widget_group_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('dashboard_widget_group_delete', 'temp'); + + //set message + message::add($text['message-delete']); + } + } + } + +} diff --git a/core/databases/resources/classes/databases.php b/core/databases/resources/classes/databases.php index 38eb97ce42..8307da2ed4 100644 --- a/core/databases/resources/classes/databases.php +++ b/core/databases/resources/classes/databases.php @@ -25,149 +25,161 @@ */ //define the databases class - class databases { +class databases { - /** - * declare constant variables - */ - const app_name = 'databases'; - const app_uuid = '8d229b6d-1383-fcec-74c6-4ce1682479e2'; + /** + * declare constant variables + */ + const app_name = 'databases'; + const app_uuid = '8d229b6d-1383-fcec-74c6-4ce1682479e2'; - /** - * declare private variables - */ + /** + * declare private variables + */ - private $database; - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; + private $database; + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; - /** - * called when the object is created - */ - public function __construct() { + /** + * Initializes the object by setting default values and connecting to the database. + */ + public function __construct() { - //assign private variables - $this->permission_prefix = 'database_'; - $this->list_page = 'databases.php'; - $this->table = 'databases'; - $this->uuid_prefix = 'database_'; + //assign private variables + $this->permission_prefix = 'database_'; + $this->list_page = 'databases.php'; + $this->table = 'databases'; + $this->uuid_prefix = 'database_'; - //connect to the database - if (empty($this->database)) { - $this->database = database::new(); - } - - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $x => $row) { - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = uuid(); - $array[$this->table][$x]['database_description'] = trim($row['database_description'].' ('.$text['label-copy'].')'); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } + //connect to the database + if (empty($this->database)) { + $this->database = database::new(); } } + + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $x => $row) { + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = uuid(); + $array[$this->table][$x]['database_description'] = trim($row['database_description'] . ' (' . $text['label-copy'] . ')'); + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + + } + unset($records); + } + + } + } + +} diff --git a/core/default_settings/default_settings.php b/core/default_settings/default_settings.php index e20106037c..586957f835 100644 --- a/core/default_settings/default_settings.php +++ b/core/default_settings/default_settings.php @@ -230,6 +230,16 @@ } //create a function to find matching row in array and return the row or boolean + /** + * Searches for a value in an array and returns the corresponding row or boolean result. + * + * @param array $search_array The array to search in. + * @param string $field The field name to match. + * @param mixed $value The value to search for. + * @param string $type The type of result to return. Can be 'boolean' or 'row'. Defaults to 'boolean'. + * + * @return bool|mixed The found row if $type is 'row', true if the value exists and $type is 'boolean', false otherwise. + */ function find_in_array($search_array, $field, $value, $type = 'boolean') { foreach($search_array as $row) { if ($row[$field] == $value) { diff --git a/core/default_settings/resources/classes/default_settings.php b/core/default_settings/resources/classes/default_settings.php index 18a808ec16..050b8b0d95 100644 --- a/core/default_settings/resources/classes/default_settings.php +++ b/core/default_settings/resources/classes/default_settings.php @@ -27,309 +27,333 @@ /** * default_settings class */ - class default_settings { +class default_settings { - /** - * declare constant variables - */ - const app_name = 'default_settings'; - const app_uuid = '2c2453c0-1bea-4475-9f44-4d969650de09'; + /** + * declare constant variables + */ + const app_name = 'default_settings'; + const app_uuid = '2c2453c0-1bea-4475-9f44-4d969650de09'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * declare private variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $location; + /** + * declare private variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $location; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign the variables - $this->name = 'default_setting'; - $this->table = 'default_settings'; - $this->toggle_field = 'default_setting_enabled'; - $this->toggle_values = ['true','false']; - $this->location = 'default_settings.php'; - } + //assign the variables + $this->name = 'default_setting'; + $this->table = 'default_settings'; + $this->toggle_field = 'default_setting_enabled'; + $this->toggle_values = ['true', 'false']; + $this->location = 'default_settings.php'; + } - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - } + //increment the id + $x++; + } - //increment the id - $x++; - } + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //set message + message::add($text['message-delete']); + } + unset($records); } } + } - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); } } + } - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = $record['uuid']; - } - } - - //copy settings - if (is_array($uuids) && sizeof($uuids) > 0) { - $settings_copied = 0; - foreach ($uuids as $x => $uuid) { - - // get default setting from db - $sql = "select * from v_default_settings "; - $sql .= "where default_setting_uuid = :default_setting_uuid "; - $parameters['default_setting_uuid'] = $uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && sizeof($row) != 0) { - $default_setting_category = $row["default_setting_category"]; - $default_setting_subcategory = $row["default_setting_subcategory"]; - $default_setting_name = $row["default_setting_name"]; - $default_setting_value = $row["default_setting_value"]; - $default_setting_order = $row["default_setting_order"]; - $default_setting_enabled = $row["default_setting_enabled"]; - $default_setting_description = $row["default_setting_description"]; - $default_setting = $row; // all values - } - unset($sql, $parameters, $row); - - //set a random password for http_auth_password - if ($default_setting_subcategory == "http_auth_password") { - $default_setting_value = generate_password(); - } - - //copy to domain - if (is_uuid($this->domain_uuid)) { - - // check if exists - $sql = "select domain_setting_uuid from v_domain_settings "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and domain_setting_category = :domain_setting_category "; - $sql .= "and domain_setting_subcategory = :domain_setting_subcategory "; - $sql .= "and domain_setting_name = :domain_setting_name "; - $sql .= "and domain_setting_name <> 'array' "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['domain_setting_category'] = $default_setting_category; - $parameters['domain_setting_subcategory'] = $default_setting_subcategory; - $parameters['domain_setting_name'] = $default_setting_name; - $target_domain_setting_uuid = $this->database->select($sql, $parameters, 'column'); - $message = $this->database->message; - - $action = is_uuid($target_domain_setting_uuid) ? 'update' : 'add'; - unset($sql, $parameters); - - // fix null - $default_setting_order = $default_setting_order != '' ? $default_setting_order : null; - - //begin array - $array['domain_settings'][$x]['domain_uuid'] = $this->domain_uuid; - $array['domain_settings'][$x]['domain_setting_category'] = $default_setting_category; - $array['domain_settings'][$x]['domain_setting_subcategory'] = $default_setting_subcategory; - $array['domain_settings'][$x]['domain_setting_name'] = $default_setting_name; - $array['domain_settings'][$x]['domain_setting_value'] = $default_setting_value; - $array['domain_settings'][$x]['domain_setting_order'] = $default_setting_order; - $array['domain_settings'][$x]['domain_setting_enabled'] = $default_setting_enabled ?: 0; - $array['domain_settings'][$x]['domain_setting_description'] = $default_setting_description; - - //insert - if ($action == "add" && permission_exists("domain_select") && permission_exists("domain_setting_add") && count($_SESSION['domains']) > 1) { - $array['domain_settings'][$x]['domain_setting_uuid'] = uuid(); - } - //update - if ($action == "update" && permission_exists('domain_setting_edit')) { - $array['domain_settings'][$x]['domain_setting_uuid'] = $target_domain_setting_uuid; - } - - //execute - if (is_uuid($array['domain_settings'][$x]['domain_setting_uuid'])) { - $this->database->save($array); - $message = $this->database->message; - unset($array); - - $settings_copied++; - } - - } - - //duplicate default setting - else { - - //populate and adjust array - $array['default_settings'][$x] = $default_setting; - $array['default_settings'][$x]['default_setting_uuid'] = uuid(); - $array['default_settings'][$x]['default_setting_enabled'] = $default_setting_enabled ?: 0; - $array['default_settings'][$x]['default_setting_description'] .= ' (Copy)'; - unset($array['default_settings'][$x]['insert_date']); - unset($array['default_settings'][$x]['insert_user']); - unset($array['default_settings'][$x]['update_date']); - unset($array['default_settings'][$x]['update_user']); - - //execute - $this->database->save($array); - $message = $this->database->message; - unset($array); - - $settings_copied++; - - } - - } // foreach - } - - //set message - if ($settings_copied != 0) { - message::add($text['message-copy']); - } - unset($records); - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; } - } //method - } //class + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = $record['uuid']; + } + } + + //copy settings + if (is_array($uuids) && sizeof($uuids) > 0) { + $settings_copied = 0; + foreach ($uuids as $x => $uuid) { + + // get default setting from db + $sql = "select * from v_default_settings "; + $sql .= "where default_setting_uuid = :default_setting_uuid "; + $parameters['default_setting_uuid'] = $uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && sizeof($row) != 0) { + $default_setting_category = $row["default_setting_category"]; + $default_setting_subcategory = $row["default_setting_subcategory"]; + $default_setting_name = $row["default_setting_name"]; + $default_setting_value = $row["default_setting_value"]; + $default_setting_order = $row["default_setting_order"]; + $default_setting_enabled = $row["default_setting_enabled"]; + $default_setting_description = $row["default_setting_description"]; + $default_setting = $row; // all values + } + unset($sql, $parameters, $row); + + //set a random password for http_auth_password + if ($default_setting_subcategory == "http_auth_password") { + $default_setting_value = generate_password(); + } + + //copy to domain + if (is_uuid($this->domain_uuid)) { + + // check if exists + $sql = "select domain_setting_uuid from v_domain_settings "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and domain_setting_category = :domain_setting_category "; + $sql .= "and domain_setting_subcategory = :domain_setting_subcategory "; + $sql .= "and domain_setting_name = :domain_setting_name "; + $sql .= "and domain_setting_name <> 'array' "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['domain_setting_category'] = $default_setting_category; + $parameters['domain_setting_subcategory'] = $default_setting_subcategory; + $parameters['domain_setting_name'] = $default_setting_name; + $target_domain_setting_uuid = $this->database->select($sql, $parameters, 'column'); + $message = $this->database->message; + + $action = is_uuid($target_domain_setting_uuid) ? 'update' : 'add'; + unset($sql, $parameters); + + // fix null + $default_setting_order = $default_setting_order != '' ? $default_setting_order : null; + + //begin array + $array['domain_settings'][$x]['domain_uuid'] = $this->domain_uuid; + $array['domain_settings'][$x]['domain_setting_category'] = $default_setting_category; + $array['domain_settings'][$x]['domain_setting_subcategory'] = $default_setting_subcategory; + $array['domain_settings'][$x]['domain_setting_name'] = $default_setting_name; + $array['domain_settings'][$x]['domain_setting_value'] = $default_setting_value; + $array['domain_settings'][$x]['domain_setting_order'] = $default_setting_order; + $array['domain_settings'][$x]['domain_setting_enabled'] = $default_setting_enabled ?: 0; + $array['domain_settings'][$x]['domain_setting_description'] = $default_setting_description; + + //insert + if ($action == "add" && permission_exists("domain_select") && permission_exists("domain_setting_add") && count($_SESSION['domains']) > 1) { + $array['domain_settings'][$x]['domain_setting_uuid'] = uuid(); + } + //update + if ($action == "update" && permission_exists('domain_setting_edit')) { + $array['domain_settings'][$x]['domain_setting_uuid'] = $target_domain_setting_uuid; + } + + //execute + if (is_uuid($array['domain_settings'][$x]['domain_setting_uuid'])) { + $this->database->save($array); + $message = $this->database->message; + unset($array); + + $settings_copied++; + } + + } //duplicate default setting + else { + + //populate and adjust array + $array['default_settings'][$x] = $default_setting; + $array['default_settings'][$x]['default_setting_uuid'] = uuid(); + $array['default_settings'][$x]['default_setting_enabled'] = $default_setting_enabled ?: 0; + $array['default_settings'][$x]['default_setting_description'] .= ' (Copy)'; + unset($array['default_settings'][$x]['insert_date']); + unset($array['default_settings'][$x]['insert_user']); + unset($array['default_settings'][$x]['update_date']); + unset($array['default_settings'][$x]['update_user']); + + //execute + $this->database->save($array); + $message = $this->database->message; + unset($array); + + $settings_copied++; + + } + + } // foreach + } + + //set message + if ($settings_copied != 0) { + message::add($text['message-copy']); + } + unset($records); + } + } + } //method + +} //class diff --git a/core/domain_settings/resources/classes/domain_settings.php b/core/domain_settings/resources/classes/domain_settings.php index 5c6aed2715..ee79db594f 100644 --- a/core/domain_settings/resources/classes/domain_settings.php +++ b/core/domain_settings/resources/classes/domain_settings.php @@ -25,375 +25,401 @@ */ //define the domain settings class - class domain_settings { +class domain_settings { - /** - * declare constant variables - */ - const app_name = 'domain_settings'; - const app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71'; + /** + * declare constant variables + */ + const app_name = 'domain_settings'; + const app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71'; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_name; - /** - * declare public variables - */ - public $domain_uuid; - public $domain_uuid_target; + /** + * declare public variables + */ + public $domain_uuid; + public $domain_uuid_target; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign private variables - $this->permission_prefix = 'domain_setting_'; - $this->list_page = PROJECT_PATH."/core/domains/domain_edit.php?id=".urlencode($this->domain_uuid ?? ''); - $this->table = 'domain_settings'; - $this->uuid_prefix = 'domain_setting_'; - $this->toggle_field = 'domain_setting_enabled'; - $this->toggle_values = ['true','false']; - } + //assign private variables + $this->permission_prefix = 'domain_setting_'; + $this->list_page = PROJECT_PATH . "/core/domains/domain_edit.php?id=" . urlencode($this->domain_uuid ?? ''); + $this->table = 'domain_settings'; + $this->uuid_prefix = 'domain_setting_'; + $this->toggle_field = 'domain_setting_enabled'; + $this->toggle_values = ['true', 'false']; + } - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate('/core/domain_settings/domain_settings.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //validate the token + $token = new token; + if (!$token->validate('/core/domain_settings/domain_settings.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; } + } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } + //execute delete + $this->database->delete($array); + unset($array); - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //set message + message::add($text['message-delete']); + } + unset($records); } } + } - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/core/domain_settings/domain_settings.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - if (is_array($states) && @sizeof($states) != 0) { - $x = 0; - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } + //add multi-lingual support + $language = new text; + $text = $language->get(); + //validate the token + $token = new token; + if (!$token->validate('/core/domain_settings/domain_settings.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + if (is_array($states) && @sizeof($states) != 0) { + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add') && permission_exists('domain_select') && count($_SESSION['domains']) > 1) { + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + * @throws \Random\RandomException + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add') && permission_exists('domain_select') && count($_SESSION['domains']) > 1) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate('/core/domain_settings/domain_settings.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = $record['uuid']; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - - $settings_copied = 0; - - //to different domain - if (is_uuid($this->domain_uuid_target)) { - - foreach ($uuids as $uuid) { - - //get domain setting from db - $sql = "select * from v_domain_settings "; - $sql .= "where domain_setting_uuid = :domain_setting_uuid "; - $parameters['domain_setting_uuid'] = $uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && sizeof($row) != 0) { - $domain_setting_category = $row["domain_setting_category"]; - $domain_setting_subcategory = $row["domain_setting_subcategory"]; - $domain_setting_name = $row["domain_setting_name"]; - $domain_setting_value = $row["domain_setting_value"]; - $domain_setting_order = $row["domain_setting_order"]; - $domain_setting_enabled = $row["domain_setting_enabled"]; - $domain_setting_description = $row["domain_setting_description"]; - } - unset($sql, $parameters, $row); - - //set a random password for http_auth_password - if ($domain_setting_subcategory == "http_auth_password") { - $domain_setting_value = generate_password(); - } - - //target is different domain, check if exists - if ($this->domain_uuid_target != $this->domain_uuid) { - $sql = "select domain_setting_uuid from v_domain_settings "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and domain_setting_category = :domain_setting_category "; - $sql .= "and domain_setting_subcategory = :domain_setting_subcategory "; - $sql .= "and domain_setting_name = :domain_setting_name "; - $sql .= "and domain_setting_name <> 'array' "; - $parameters['domain_uuid'] = $this->domain_uuid_target; - $parameters['domain_setting_category'] = $domain_setting_category; - $parameters['domain_setting_subcategory'] = $domain_setting_subcategory; - $parameters['domain_setting_name'] = $domain_setting_name; - $target_domain_setting_uuid = $this->database->select($sql, $parameters, 'column'); - - $action = is_uuid($target_domain_setting_uuid) ? 'update' : 'add'; - unset($sql, $parameters); - } - //target is same domain, duplicate - else { - $action = 'add'; - } - - // fix null - $domain_setting_order = $domain_setting_order != '' ? $domain_setting_order : null; - - //begin array - $array['domain_settings'][0]['domain_uuid'] = $this->domain_uuid_target; - $array['domain_settings'][0]['domain_setting_category'] = $domain_setting_category; - $array['domain_settings'][0]['domain_setting_subcategory'] = $domain_setting_subcategory; - $array['domain_settings'][0]['domain_setting_name'] = $domain_setting_name; - $array['domain_settings'][0]['domain_setting_value'] = $domain_setting_value; - $array['domain_settings'][0]['domain_setting_order'] = $domain_setting_order; - $array['domain_settings'][0]['domain_setting_enabled'] = $domain_setting_enabled ?: 0; - $array['domain_settings'][0]['domain_setting_description'] = $domain_setting_description; - - //insert - if ($action == "add" && permission_exists("domain_setting_add")) { - $array['domain_settings'][0]['domain_setting_uuid'] = uuid(); - } - //update - if ($action == "update" && permission_exists('domain_setting_edit')) { - $array['domain_settings'][0]['domain_setting_uuid'] = $target_domain_setting_uuid; - } - - //execute - if (is_uuid($array['domain_settings'][0]['domain_setting_uuid'])) { - $this->database->app_name = 'domain_settings'; - $this->database->app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71'; - $this->database->save($array); - unset($array); - - $settings_copied++; - } - - } //foreach - } //if - - //to default settings - else if ($this->domain_uuid_target == 'default') { - foreach ($uuids as $uuid) { - - //get domain setting from db - $sql = "select * from v_domain_settings "; - $sql .= "where domain_setting_uuid = :domain_setting_uuid "; - $parameters['domain_setting_uuid'] = $uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && sizeof($row) != 0) { - $domain_setting_category = $row["domain_setting_category"]; - $domain_setting_subcategory = $row["domain_setting_subcategory"]; - $domain_setting_name = $row["domain_setting_name"]; - $domain_setting_value = $row["domain_setting_value"]; - $domain_setting_order = $row["domain_setting_order"]; - $domain_setting_enabled = $row["domain_setting_enabled"]; - $domain_setting_description = $row["domain_setting_description"]; - } - unset($sql, $parameters, $row); - - //set a random password for http_auth_password - if ($domain_setting_subcategory == "http_auth_password") { - $domain_setting_value = generate_password(); - } - - // check if exists - $sql = "select default_setting_uuid from v_default_settings "; - $sql .= "where default_setting_category = :default_setting_category "; - $sql .= "and default_setting_subcategory = :default_setting_subcategory "; - $sql .= "and default_setting_name = :default_setting_name "; - $sql .= "and default_setting_name <> 'array' "; - $parameters['default_setting_category'] = $domain_setting_category; - $parameters['default_setting_subcategory'] = $domain_setting_subcategory; - $parameters['default_setting_name'] = $domain_setting_name; - $target_default_setting_uuid = $this->database->select($sql, $parameters, 'column'); - - $action = is_uuid($target_default_setting_uuid) ? 'update' : 'add'; - unset($sql, $parameters); - - // fix null - $domain_setting_order = $domain_setting_order != '' ? $domain_setting_order : null; - - //begin array - $array['default_settings'][0]['default_setting_category'] = $domain_setting_category; - $array['default_settings'][0]['default_setting_subcategory'] = $domain_setting_subcategory; - $array['default_settings'][0]['default_setting_name'] = $domain_setting_name; - $array['default_settings'][0]['default_setting_value'] = $domain_setting_value; - $array['default_settings'][0]['default_setting_order'] = $domain_setting_order; - $array['default_settings'][0]['default_setting_enabled'] = $domain_setting_enabled; - $array['default_settings'][0]['default_setting_description'] = $domain_setting_description; - - //insert - if ($action == "add" && permission_exists("default_setting_add")) { - $array['default_settings'][0]['default_setting_uuid'] = uuid(); - } - //update - if ($action == "update" && permission_exists('default_setting_edit')) { - $array['default_settings'][0]['default_setting_uuid'] = $target_default_setting_uuid; - } - - //execute - if (is_uuid($array['default_settings'][0]['default_setting_uuid'])) { - $this->database->app_name = 'domain_settings'; - $this->database->app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71'; - $this->database->save($array); - unset($array); - - $settings_copied++; - } - - } //foreach - } //if - - // set message - message::add($text['message-copy'].": ".escape($settings_copied)); - - } - - } - - unset($records); + //validate the token + $token = new token; + if (!$token->validate('/core/domain_settings/domain_settings.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - } //method - } //class + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = $record['uuid']; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + + $settings_copied = 0; + + //to different domain + if (is_uuid($this->domain_uuid_target)) { + + foreach ($uuids as $uuid) { + + //get domain setting from db + $sql = "select * from v_domain_settings "; + $sql .= "where domain_setting_uuid = :domain_setting_uuid "; + $parameters['domain_setting_uuid'] = $uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && sizeof($row) != 0) { + $domain_setting_category = $row["domain_setting_category"]; + $domain_setting_subcategory = $row["domain_setting_subcategory"]; + $domain_setting_name = $row["domain_setting_name"]; + $domain_setting_value = $row["domain_setting_value"]; + $domain_setting_order = $row["domain_setting_order"]; + $domain_setting_enabled = $row["domain_setting_enabled"]; + $domain_setting_description = $row["domain_setting_description"]; + } + unset($sql, $parameters, $row); + + //set a random password for http_auth_password + if ($domain_setting_subcategory == "http_auth_password") { + $domain_setting_value = generate_password(); + } + + //target is different domain, check if exists + if ($this->domain_uuid_target != $this->domain_uuid) { + $sql = "select domain_setting_uuid from v_domain_settings "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and domain_setting_category = :domain_setting_category "; + $sql .= "and domain_setting_subcategory = :domain_setting_subcategory "; + $sql .= "and domain_setting_name = :domain_setting_name "; + $sql .= "and domain_setting_name <> 'array' "; + $parameters['domain_uuid'] = $this->domain_uuid_target; + $parameters['domain_setting_category'] = $domain_setting_category; + $parameters['domain_setting_subcategory'] = $domain_setting_subcategory; + $parameters['domain_setting_name'] = $domain_setting_name; + $target_domain_setting_uuid = $this->database->select($sql, $parameters, 'column'); + + $action = is_uuid($target_domain_setting_uuid) ? 'update' : 'add'; + unset($sql, $parameters); + } //target is same domain, duplicate + else { + $action = 'add'; + } + + // fix null + $domain_setting_order = $domain_setting_order != '' ? $domain_setting_order : null; + + //begin array + $array['domain_settings'][0]['domain_uuid'] = $this->domain_uuid_target; + $array['domain_settings'][0]['domain_setting_category'] = $domain_setting_category; + $array['domain_settings'][0]['domain_setting_subcategory'] = $domain_setting_subcategory; + $array['domain_settings'][0]['domain_setting_name'] = $domain_setting_name; + $array['domain_settings'][0]['domain_setting_value'] = $domain_setting_value; + $array['domain_settings'][0]['domain_setting_order'] = $domain_setting_order; + $array['domain_settings'][0]['domain_setting_enabled'] = $domain_setting_enabled ?: 0; + $array['domain_settings'][0]['domain_setting_description'] = $domain_setting_description; + + //insert + if ($action == "add" && permission_exists("domain_setting_add")) { + $array['domain_settings'][0]['domain_setting_uuid'] = uuid(); + } + //update + if ($action == "update" && permission_exists('domain_setting_edit')) { + $array['domain_settings'][0]['domain_setting_uuid'] = $target_domain_setting_uuid; + } + + //execute + if (is_uuid($array['domain_settings'][0]['domain_setting_uuid'])) { + $this->database->app_name = 'domain_settings'; + $this->database->app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71'; + $this->database->save($array); + unset($array); + + $settings_copied++; + } + + } //foreach + } //if + + //to default settings + elseif ($this->domain_uuid_target == 'default') { + foreach ($uuids as $uuid) { + + //get domain setting from db + $sql = "select * from v_domain_settings "; + $sql .= "where domain_setting_uuid = :domain_setting_uuid "; + $parameters['domain_setting_uuid'] = $uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && sizeof($row) != 0) { + $domain_setting_category = $row["domain_setting_category"]; + $domain_setting_subcategory = $row["domain_setting_subcategory"]; + $domain_setting_name = $row["domain_setting_name"]; + $domain_setting_value = $row["domain_setting_value"]; + $domain_setting_order = $row["domain_setting_order"]; + $domain_setting_enabled = $row["domain_setting_enabled"]; + $domain_setting_description = $row["domain_setting_description"]; + } + unset($sql, $parameters, $row); + + //set a random password for http_auth_password + if ($domain_setting_subcategory == "http_auth_password") { + $domain_setting_value = generate_password(); + } + + // check if exists + $sql = "select default_setting_uuid from v_default_settings "; + $sql .= "where default_setting_category = :default_setting_category "; + $sql .= "and default_setting_subcategory = :default_setting_subcategory "; + $sql .= "and default_setting_name = :default_setting_name "; + $sql .= "and default_setting_name <> 'array' "; + $parameters['default_setting_category'] = $domain_setting_category; + $parameters['default_setting_subcategory'] = $domain_setting_subcategory; + $parameters['default_setting_name'] = $domain_setting_name; + $target_default_setting_uuid = $this->database->select($sql, $parameters, 'column'); + + $action = is_uuid($target_default_setting_uuid) ? 'update' : 'add'; + unset($sql, $parameters); + + // fix null + $domain_setting_order = $domain_setting_order != '' ? $domain_setting_order : null; + + //begin array + $array['default_settings'][0]['default_setting_category'] = $domain_setting_category; + $array['default_settings'][0]['default_setting_subcategory'] = $domain_setting_subcategory; + $array['default_settings'][0]['default_setting_name'] = $domain_setting_name; + $array['default_settings'][0]['default_setting_value'] = $domain_setting_value; + $array['default_settings'][0]['default_setting_order'] = $domain_setting_order; + $array['default_settings'][0]['default_setting_enabled'] = $domain_setting_enabled; + $array['default_settings'][0]['default_setting_description'] = $domain_setting_description; + + //insert + if ($action == "add" && permission_exists("default_setting_add")) { + $array['default_settings'][0]['default_setting_uuid'] = uuid(); + } + //update + if ($action == "update" && permission_exists('default_setting_edit')) { + $array['default_settings'][0]['default_setting_uuid'] = $target_default_setting_uuid; + } + + //execute + if (is_uuid($array['default_settings'][0]['default_setting_uuid'])) { + $this->database->app_name = 'domain_settings'; + $this->database->app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71'; + $this->database->save($array); + unset($array); + + $settings_copied++; + } + + } //foreach + } //if + + // set message + message::add($text['message-copy'] . ": " . escape($settings_copied)); + + } + + } + + unset($records); + } + } //method + +} //class diff --git a/core/email_templates/resources/classes/email_templates.php b/core/email_templates/resources/classes/email_templates.php index 831e717cc0..8a1412e429 100644 --- a/core/email_templates/resources/classes/email_templates.php +++ b/core/email_templates/resources/classes/email_templates.php @@ -25,244 +25,270 @@ */ //define the email templates class - class email_templates { +class email_templates { - /** - * declare constant variables - */ - const app_name = 'email_templates'; - const app_uuid = '8173e738-2523-46d5-8943-13883befd2fd'; + /** + * declare constant variables + */ + const app_name = 'email_templates'; + const app_uuid = '8173e738-2523-46d5-8943-13883befd2fd'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - - //assign private variables - $this->permission_prefix = 'email_template_'; - $this->list_page = 'email_templates.php'; - $this->table = 'email_templates'; - $this->uuid_prefix = 'email_template_'; - $this->toggle_field = 'template_enabled'; - $this->toggle_values = ['true','false']; - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $x => $row) { - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = uuid(); - $array[$this->table][$x]['template_description'] = trim($row['template_description'].' ('.$text['label-copy'].')'); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); + //assign private variables + $this->permission_prefix = 'email_template_'; + $this->list_page = 'email_templates.php'; + $this->table = 'email_templates'; + $this->uuid_prefix = 'email_template_'; + $this->toggle_field = 'template_enabled'; + $this->toggle_values = ['true', 'false']; } + + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $x => $row) { + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = uuid(); + $array[$this->table][$x]['template_description'] = trim($row['template_description'] . ' (' . $text['label-copy'] . ')'); + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + + } + unset($records); + } + + } + } + +} diff --git a/core/groups/resources/classes/permission.php b/core/groups/resources/classes/permission.php index 362cf587d1..ca17356555 100644 --- a/core/groups/resources/classes/permission.php +++ b/core/groups/resources/classes/permission.php @@ -25,193 +25,216 @@ */ //define the permission class - class permission { +class permission { - /** - * declare constant variables - */ - const app_name = 'groups'; - const app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84'; + /** + * declare constant variables + */ + const app_name = 'groups'; + const app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84'; - /** - * declare private variables - */ + /** + * declare private variables + */ - private $database; - private $database_group_permissions; + private $database; + private $database_group_permissions; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set objects - $this->database = $setting_array['database'] ?? database::new(); + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set objects + $this->database = $setting_array['database'] ?? database::new(); + } + + //delete the permissions + + /** + * Deletes unprotected group permissions from the database. + * + * This method retrieves a list of apps and their associated permissions, then deletes any permissions that are not protected. + * + * @return void + */ + function delete() { + + //get the $apps array from the installed apps from the core and mod directories + $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php"); + $x = 0; + foreach ($config_list as $config_path) { + include($config_path); + $x++; } - //delete the permissions - function delete() { + //initialize array + $group_name_array = []; - //get the $apps array from the installed apps from the core and mod directories - $config_list = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_config.php"); - $x = 0; - foreach ($config_list as $config_path) { - include($config_path); - $x++; + //restore default permissions + $x = 0; + foreach ($apps as $row) { + if (!empty($row['permissions']) && is_array($row['permissions']) && @sizeof($row['permissions']) != 0) { + foreach ($row['permissions'] as $permission) { + if (!empty($permission['groups']) && is_array($permission['groups'])) { + foreach ($permission['groups'] as $group_name) { + if (is_array($group_name_array) || !in_array($group_name, $group_name_array)) { + $group_name_array[] = $group_name; + } + } } + } + } + } + $group_names = "'" . implode("','", $group_name_array) . "'"; - //initialize array - $group_name_array = array(); + //delete unprotected permissions + $sql = "delete from v_group_permissions as p "; + $sql .= "where group_name in ( "; + $sql .= " select group_name "; + $sql .= " from v_groups "; + $sql .= " where group_protected <> true "; + $sql .= " and group_name in (" . $group_names . ") "; + $sql .= ")"; + $sql .= "and (permission_protected <> 'true' or permission_protected is null)"; + $result = $this->database->select($sql); - //restore default permissions - $x = 0; - foreach ($apps as $row) { - if (!empty($row['permissions']) && is_array($row['permissions']) && @sizeof($row['permissions']) != 0) { - foreach ($row['permissions'] as $permission) { - if (!empty($permission['groups']) && is_array($permission['groups'])) { - foreach ($permission['groups'] as $group_name) { - if (is_array($group_name_array) || !in_array($group_name, $group_name_array)) { - $group_name_array[] = $group_name; + //get the group_permissons + /* + $sql = "select * from v_group_permissions as p "; + $sql .= "where group_name in ( "; + $sql .= " select group_name "; + $sql .= " from v_groups "; + $sql .= " where group_protected <> true "; + $sql .= " and group_name in (".$group_names.") "; + $sql .= ");"; + $group_permissions = $this->database->select($sql, null, 'all'); + */ + + //delete unprotected group permissions + /* + if (is_array($group_permissions) && sizeof($group_permissions) > 0) { + $x = 0; + foreach ($group_permissions as $row) { + //build delete array + $array['group_permissions'][$x]['group_permission_uuid'] = $row['group_permission_uuid']; + $array['group_permissions'][$x]['domain_uuid'] = ($row['domain_uuid'] != '') ? $row['domain_uuid'] : null; + $x++; + } + if (is_array($array) && @sizeof($array) != 0) { + //grant temporary permissions + $p = permissions::new(); + $p->add('group_permission_delete', 'temp'); + //execute delete + $this->database->delete($array); + unset($array); + //revoke temporary permissions + $p->delete('group_permission_delete', 'temp'); + } + } + */ + } + + //restore the permissions + + /** + * Restore default group and permission settings. + * + * This method restores the default groups and permissions by deleting existing unprotected permissions, + * adding default groups if none exist, retrieving remaining permissions from installed apps, + * and inserting default permissions into the database. + * + * @return void + * @see permission::delete() + */ + function restore() { + + //if the are no groups add the default groups + $sql = "select * from v_groups "; + $sql .= "where domain_uuid is null "; + $groups = $this->database->select($sql, null, 'all'); + + //delete the group permissions + $this->delete(); + + //get the remaining group permissions + $sql = "select permission_name, group_name from v_group_permissions "; + $this->database_group_permissions = $this->database->select($sql, null, 'all'); + + //get the $apps array from the installed apps from the core and mod directories + $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php"); + $x = 0; + foreach ($config_list as $config_path) { + include($config_path); + $x++; + } + + //restore default permissions + $x = 0; + foreach ($apps as $row) { + if (!empty($row['permissions']) && is_array($row['permissions']) && @sizeof($row['permissions']) != 0) { + foreach ($row['permissions'] as $permission) { + //set the variables + if (!empty($permission['groups'])) { + foreach ($permission['groups'] as $group_name) { + //check group protection + $group_uuid = null; + $group_protected = false; + if (is_array($groups)) { + foreach ($groups as $group) { + if ($group['group_name'] == $group_name) { + $group_uuid = $group['group_uuid']; + $group_protected = $group['group_protected']; + break; + } + } + } + if (!$group_protected) { + // check if the item is not currently in the database + $exists = false; + foreach ($this->database_group_permissions as $i => $group_permission) { + if ($group_permission['permission_name'] == $permission['name']) { + if ($group_permission['group_name'] == $group_name) { + $exists = true; + break; } } } + if (!$exists) { + //build default permissions insert array + $array['group_permissions'][$x]['group_permission_uuid'] = uuid(); + $array['group_permissions'][$x]['permission_name'] = $permission['name']; + $array['group_permissions'][$x]['permission_protected'] = 'false'; + $array['group_permissions'][$x]['permission_assigned'] = 'true'; + $array['group_permissions'][$x]['group_name'] = $group_name; + $array['group_permissions'][$x]['group_uuid'] = $group_uuid; + $x++; + } } } } - $group_names = "'".implode("','", $group_name_array)."'"; - - //delete unprotected permissions - $sql = "delete from v_group_permissions as p "; - $sql .= "where group_name in ( "; - $sql .= " select group_name "; - $sql .= " from v_groups "; - $sql .= " where group_protected <> true "; - $sql .= " and group_name in (".$group_names.") "; - $sql .= ")"; - $sql .= "and (permission_protected <> 'true' or permission_protected is null)"; - $result = $this->database->select($sql); - - //get the group_permissons - /* - $sql = "select * from v_group_permissions as p "; - $sql .= "where group_name in ( "; - $sql .= " select group_name "; - $sql .= " from v_groups "; - $sql .= " where group_protected <> true "; - $sql .= " and group_name in (".$group_names.") "; - $sql .= ");"; - $group_permissions = $this->database->select($sql, null, 'all'); - */ - - //delete unprotected group permissions - /* - if (is_array($group_permissions) && sizeof($group_permissions) > 0) { - $x = 0; - foreach ($group_permissions as $row) { - //build delete array - $array['group_permissions'][$x]['group_permission_uuid'] = $row['group_permission_uuid']; - $array['group_permissions'][$x]['domain_uuid'] = ($row['domain_uuid'] != '') ? $row['domain_uuid'] : null; - $x++; - } - if (is_array($array) && @sizeof($array) != 0) { - //grant temporary permissions - $p = permissions::new(); - $p->add('group_permission_delete', 'temp'); - //execute delete - $this->database->delete($array); - unset($array); - //revoke temporary permissions - $p->delete('group_permission_delete', 'temp'); - } - } - */ + } } + } - //restore the permissions - function restore() { + if (is_array($array) && @sizeof($array)) { + //grant temporary permissions + $p = permissions::new(); + $p->add('group_permission_add', 'temp'); - //if the are no groups add the default groups - $sql = "select * from v_groups "; - $sql .= "where domain_uuid is null "; - $groups = $this->database->select($sql, null, 'all'); + //execute insert + $this->database->save($array); + unset($array); - //delete the group permissions - $this->delete(); - - //get the remaining group permissions - $sql = "select permission_name, group_name from v_group_permissions "; - $this->database_group_permissions = $this->database->select($sql, null, 'all'); - - //get the $apps array from the installed apps from the core and mod directories - $config_list = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_config.php"); - $x = 0; - foreach ($config_list as $config_path) { - include($config_path); - $x++; - } - - //restore default permissions - $x = 0; - foreach ($apps as $row) { - if (!empty($row['permissions']) && is_array($row['permissions']) && @sizeof($row['permissions']) != 0) { - foreach ($row['permissions'] as $permission) { - //set the variables - if (!empty($permission['groups'])) { - foreach ($permission['groups'] as $group_name) { - //check group protection - $group_uuid = null; - $group_protected = false; - if (is_array($groups)) { - foreach ($groups as $group) { - if ($group['group_name'] == $group_name) { - $group_uuid = $group['group_uuid']; - $group_protected = $group['group_protected']; - break; - } - } - } - if (!$group_protected) { - // check if the item is not currently in the database - $exists = false; - foreach ($this->database_group_permissions as $i => $group_permission) { - if ($group_permission['permission_name'] == $permission['name']) { - if ($group_permission['group_name'] == $group_name) { - $exists = true; - break; - } - } - } - if (!$exists) { - //build default permissions insert array - $array['group_permissions'][$x]['group_permission_uuid'] = uuid(); - $array['group_permissions'][$x]['permission_name'] = $permission['name']; - $array['group_permissions'][$x]['permission_protected'] = 'false'; - $array['group_permissions'][$x]['permission_assigned'] = 'true'; - $array['group_permissions'][$x]['group_name'] = $group_name; - $array['group_permissions'][$x]['group_uuid'] = $group_uuid; - $x++; - } - } - } - } - } - } - } - - if (is_array($array) && @sizeof($array)) { - //grant temporary permissions - $p = permissions::new(); - $p->add('group_permission_add', 'temp'); - - //execute insert - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('group_permission_add', 'temp'); - } - - } + //revoke temporary permissions + $p->delete('group_permission_add', 'temp'); + } } +} + ?> diff --git a/core/install/resources/classes/install.php b/core/install/resources/classes/install.php index 88c7307194..e9ff59c3d1 100644 --- a/core/install/resources/classes/install.php +++ b/core/install/resources/classes/install.php @@ -1,174 +1,174 @@ Used to create the config.conf file.

- *

BSD /usr/local/etc/fusionpbx

- *

Linux /etc/fusionpbx

- * @return boolean - */ - public function config() { + /** + * Used to create the config.conf file using paths based on the operating system. + * + * @return boolean true if the configuration file is successfully created, false otherwise. + */ + public function config() { - //set the default config file location - $os = strtoupper(substr(PHP_OS, 0, 3)); - switch ($os) { - case "FRE": - case "OPE": - case "NET": - case "BSD": - $config_path = '/usr/local/etc/fusionpbx'; - $config_file = $config_path.'/config.conf'; + //set the default config file location + $os = strtoupper(substr(PHP_OS, 0, 3)); + switch ($os) { + case "FRE": + case "OPE": + case "NET": + case "BSD": + $config_path = '/usr/local/etc/fusionpbx'; + $config_file = $config_path . '/config.conf'; $document_root = '/usr/local/www/fusionpbx'; - $conf_dir = '/usr/local/etc/freeswitch'; - $sounds_dir = '/usr/share/freeswitch/sounds'; - $database_dir = '/var/lib/freeswitch/db'; + $conf_dir = '/usr/local/etc/freeswitch'; + $sounds_dir = '/usr/share/freeswitch/sounds'; + $database_dir = '/var/lib/freeswitch/db'; $recordings_dir = '/var/lib/freeswitch/recordings'; - $storage_dir = '/var/lib/freeswitch/storage'; - $voicemail_dir = '/var/lib/freeswitch/storage/voicemail'; - $scripts_dir = '/usr/share/freeswitch/scripts'; - $php_dir = PHP_BINDIR; + $storage_dir = '/var/lib/freeswitch/storage'; + $voicemail_dir = '/var/lib/freeswitch/storage/voicemail'; + $scripts_dir = '/usr/share/freeswitch/scripts'; + $php_dir = PHP_BINDIR; $cache_location = '/var/cache/fusionpbx'; break; case "LIN": - $config_path = '/etc/fusionpbx/'; - $config_file = $config_path.'/config.conf'; + $config_path = '/etc/fusionpbx/'; + $config_file = $config_path . '/config.conf'; $document_root = '/var/www/fusionpbx'; - $conf_dir = '/etc/freeswitch'; - $sounds_dir = '/usr/share/freeswitch/sounds'; - $database_dir = '/var/lib/freeswitch/db'; + $conf_dir = '/etc/freeswitch'; + $sounds_dir = '/usr/share/freeswitch/sounds'; + $database_dir = '/var/lib/freeswitch/db'; $recordings_dir = '/var/lib/freeswitch/recordings'; - $storage_dir = '/var/lib/freeswitch/storage'; - $voicemail_dir = '/var/lib/freeswitch/storage/voicemail'; - $scripts_dir = '/usr/share/freeswitch/scripts'; - $php_dir = PHP_BINDIR; + $storage_dir = '/var/lib/freeswitch/storage'; + $voicemail_dir = '/var/lib/freeswitch/storage/voicemail'; + $scripts_dir = '/usr/share/freeswitch/scripts'; + $php_dir = PHP_BINDIR; $cache_location = '/var/cache/fusionpbx'; break; case "WIN": - $system_drive = getenv('SystemDrive'); - $config_path = $system_drive . DIRECTORY_SEPARATOR . 'ProgramData' . DIRECTORY_SEPARATOR . 'fusionpbx' ; - $config_file = $config_path.DIRECTORY_SEPARATOR.'config.conf'; + $system_drive = getenv('SystemDrive'); + $config_path = $system_drive . DIRECTORY_SEPARATOR . 'ProgramData' . DIRECTORY_SEPARATOR . 'fusionpbx'; + $config_file = $config_path . DIRECTORY_SEPARATOR . 'config.conf'; $document_root = $_SERVER["DOCUMENT_ROOT"]; - $conf_dir = $_SERVER['ProgramFiles'].DIRECTORY_SEPARATOR.'freeswitch'.DIRECTORY_SEPARATOR.'conf'; - $sounds_dir = $_SERVER['ProgramFiles'].DIRECTORY_SEPARATOR.'freeswitch'.DIRECTORY_SEPARATOR.'sounds'; - $database_dir = $_SERVER['ProgramFiles'].DIRECTORY_SEPARATOR.'freeswitch'.DIRECTORY_SEPARATOR.'db'; - $recordings_dir = $_SERVER['ProgramFiles'].DIRECTORY_SEPARATOR.'freeswitch'.DIRECTORY_SEPARATOR.'recordings'; - $storage_dir = $_SERVER['ProgramFiles'].DIRECTORY_SEPARATOR.'freeswitch'.DIRECTORY_SEPARATOR.'storage'; - $voicemail_dir = $_SERVER['ProgramFiles'].DIRECTORY_SEPARATOR.'freeswitch'.DIRECTORY_SEPARATOR.'voicemail'; - $scripts_dir = $_SERVER['ProgramFiles'].DIRECTORY_SEPARATOR.'freeswitch'.DIRECTORY_SEPARATOR.'scripts'; - $php_dir = dirname(PHP_BINARY); - $cache_location = dirname($_SERVER['DOCUMENT_ROOT']).DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR.'fusionpbx'; + $conf_dir = $_SERVER['ProgramFiles'] . DIRECTORY_SEPARATOR . 'freeswitch' . DIRECTORY_SEPARATOR . 'conf'; + $sounds_dir = $_SERVER['ProgramFiles'] . DIRECTORY_SEPARATOR . 'freeswitch' . DIRECTORY_SEPARATOR . 'sounds'; + $database_dir = $_SERVER['ProgramFiles'] . DIRECTORY_SEPARATOR . 'freeswitch' . DIRECTORY_SEPARATOR . 'db'; + $recordings_dir = $_SERVER['ProgramFiles'] . DIRECTORY_SEPARATOR . 'freeswitch' . DIRECTORY_SEPARATOR . 'recordings'; + $storage_dir = $_SERVER['ProgramFiles'] . DIRECTORY_SEPARATOR . 'freeswitch' . DIRECTORY_SEPARATOR . 'storage'; + $voicemail_dir = $_SERVER['ProgramFiles'] . DIRECTORY_SEPARATOR . 'freeswitch' . DIRECTORY_SEPARATOR . 'voicemail'; + $scripts_dir = $_SERVER['ProgramFiles'] . DIRECTORY_SEPARATOR . 'freeswitch' . DIRECTORY_SEPARATOR . 'scripts'; + $php_dir = dirname(PHP_BINARY); + $cache_location = dirname($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'fusionpbx'; break; - } + } - //end the script if the config path is not set - if (!isset($config_path)) { - $this->message = "Config file path not found\n"; - return false; - } + //end the script if the config path is not set + if (!isset($config_path)) { + $this->message = "Config file path not found\n"; + return false; + } - //config directory is not writable - if (!is_writable($config_path)) { - $this->message = "Check permissions ".$config_path." must be writable.\n"; - return false; - } + //config directory is not writable + if (!is_writable($config_path)) { + $this->message = "Check permissions " . $config_path . " must be writable.\n"; + return false; + } - //make the config directory - if (isset($config_path)) { - system('mkdir -p '.$config_path); - } + //make the config directory + if (isset($config_path)) { + system('mkdir -p ' . $config_path); + } - //build the config file - $conf = "\n"; - $conf .= "#database system settings\n"; - $conf .= "database.0.type = pgsql\n"; - $conf .= "database.0.host = ".$this->database_host."\n"; - $conf .= "database.0.port = ".$this->database_port."\n"; - $conf .= "database.0.sslmode = prefer\n"; - $conf .= "database.0.name = ".$this->database_name."\n"; - $conf .= "database.0.username = ".$this->database_username."\n"; - $conf .= "database.0.password = ".$this->database_password."\n"; - $conf .= "\n"; - $conf .= "#database switch settings\n"; - $conf .= "database.1.type = sqlite\n"; - $conf .= "database.1.path = ".$database_dir."\n"; - $conf .= "database.1.name = core.db\n"; - //$conf .= "database.1.backend.base64 = \n"; - $conf .= "\n"; - $conf .= "#general settings\n"; - $conf .= "document.root = ".$document_root."\n"; - $conf .= "project.path =\n"; - $conf .= "temp.dir = /tmp\n"; - $conf .= "php.dir = ".$php_dir."\n"; - $conf .= "php.bin = php\n"; - $conf .= "\n"; - $conf .= "#session settings\n"; - $conf .= "session.cookie_httponly = true\n"; - $conf .= "session.cookie_secure = true\n"; - $conf .= "session.cookie_samesite = Lax\n"; - $conf .= "\n"; - $conf .= "#cache settings\n"; - $conf .= "cache.method = file\n"; - $conf .= "cache.location = ".$cache_location."\n"; - $conf .= "cache.settings = true\n"; - $conf .= "\n"; - $conf .= "#switch settings\n"; - $conf .= "switch.conf.dir = ".$conf_dir."\n"; - $conf .= "switch.sounds.dir = ".$sounds_dir."\n"; - $conf .= "switch.database.dir = ".$database_dir."\n"; - $conf .= "switch.recordings.dir = ".$recordings_dir."\n"; - $conf .= "switch.storage.dir = ".$storage_dir."\n"; - $conf .= "switch.voicemail.dir = ".$voicemail_dir."\n"; - $conf .= "switch.scripts.dir = ".$scripts_dir."\n"; - $conf .= "\n"; - $conf .= "#switch xml handler\n"; - $conf .= "xml_handler.fs_path = false\n"; - $conf .= "xml_handler.reg_as_number_alias = false\n"; - $conf .= "xml_handler.number_as_presence_id = true\n"; - $conf .= "\n"; - $conf .= "#error reporting options: user,dev,all\n"; - $conf .= "error.reporting = user\n"; + //build the config file + $conf = "\n"; + $conf .= "#database system settings\n"; + $conf .= "database.0.type = pgsql\n"; + $conf .= "database.0.host = " . $this->database_host . "\n"; + $conf .= "database.0.port = " . $this->database_port . "\n"; + $conf .= "database.0.sslmode = prefer\n"; + $conf .= "database.0.name = " . $this->database_name . "\n"; + $conf .= "database.0.username = " . $this->database_username . "\n"; + $conf .= "database.0.password = " . $this->database_password . "\n"; + $conf .= "\n"; + $conf .= "#database switch settings\n"; + $conf .= "database.1.type = sqlite\n"; + $conf .= "database.1.path = " . $database_dir . "\n"; + $conf .= "database.1.name = core.db\n"; + //$conf .= "database.1.backend.base64 = \n"; + $conf .= "\n"; + $conf .= "#general settings\n"; + $conf .= "document.root = " . $document_root . "\n"; + $conf .= "project.path =\n"; + $conf .= "temp.dir = /tmp\n"; + $conf .= "php.dir = " . $php_dir . "\n"; + $conf .= "php.bin = php\n"; + $conf .= "\n"; + $conf .= "#session settings\n"; + $conf .= "session.cookie_httponly = true\n"; + $conf .= "session.cookie_secure = true\n"; + $conf .= "session.cookie_samesite = Lax\n"; + $conf .= "\n"; + $conf .= "#cache settings\n"; + $conf .= "cache.method = file\n"; + $conf .= "cache.location = " . $cache_location . "\n"; + $conf .= "cache.settings = true\n"; + $conf .= "\n"; + $conf .= "#switch settings\n"; + $conf .= "switch.conf.dir = " . $conf_dir . "\n"; + $conf .= "switch.sounds.dir = " . $sounds_dir . "\n"; + $conf .= "switch.database.dir = " . $database_dir . "\n"; + $conf .= "switch.recordings.dir = " . $recordings_dir . "\n"; + $conf .= "switch.storage.dir = " . $storage_dir . "\n"; + $conf .= "switch.voicemail.dir = " . $voicemail_dir . "\n"; + $conf .= "switch.scripts.dir = " . $scripts_dir . "\n"; + $conf .= "\n"; + $conf .= "#switch xml handler\n"; + $conf .= "xml_handler.fs_path = false\n"; + $conf .= "xml_handler.reg_as_number_alias = false\n"; + $conf .= "xml_handler.number_as_presence_id = true\n"; + $conf .= "\n"; + $conf .= "#error reporting options: user,dev,all\n"; + $conf .= "error.reporting = user\n"; - //write the config file - $file_handle = fopen($config_file,"w"); - if(!$file_handle) { return; } - fwrite($file_handle, $conf); - fclose($file_handle); - - //if the config.conf file was saved return true - if (file_exists($config_file)) { - return true; - } - else { - return false; - } + //write the config file + $file_handle = fopen($config_file, "w"); + if (!$file_handle) { + return; + } + fwrite($file_handle, $conf); + fclose($file_handle); + //if the config.conf file was saved return true + if (file_exists($config_file)) { + return true; + } else { + return false; } } + +} diff --git a/core/menu/menu_item_list.php b/core/menu/menu_item_list.php index a4d63d4d2b..68af0a8e13 100644 --- a/core/menu/menu_item_list.php +++ b/core/menu/menu_item_list.php @@ -86,6 +86,15 @@ $tmp_menu_item_order = 0; //add the build db child menu list + /** + * Builds a child menu list from the database. + * + * @param object $database The database connection object. + * @param int $menu_item_level The current level of the menu item. + * @param string $menu_item_uuid The UUID of the parent menu item. + * + * @return void + */ function build_db_child_menu_list ($database, $menu_item_level, $menu_item_uuid) { global $settings, $menu_uuid, $list_row_edit_button; global $tmp_menu_item_order, $v_link_label_edit, $v_link_label_delete; diff --git a/core/software/resources/classes/software.php b/core/software/resources/classes/software.php index 7e36822048..93b7d1c05b 100644 --- a/core/software/resources/classes/software.php +++ b/core/software/resources/classes/software.php @@ -6,14 +6,23 @@ class software { /** - * version + * Returns the version number as a string. + * + * @return string The version number in the format 'major.minor.patch'. */ public static function version() { return '5.5.3'; } /** - * numeric_version + * Returns the version number as a single integer. + * + * This function takes the version string, splits it into its components, and combines + * them into a single integer value. The integer is calculated by multiplying each component + * by an increasing power of 100 (e.g., 10,000 for the major version, 1,000 for the minor version, + * and 100 for the patch version). + * + * @return int The numeric version number. */ public static function numeric_version() { $v = explode('.', software::version()); diff --git a/core/upgrade/upgrade.php b/core/upgrade/upgrade.php index 7522fc1e0d..af860bf640 100644 --- a/core/upgrade/upgrade.php +++ b/core/upgrade/upgrade.php @@ -578,9 +578,15 @@ } - /** - * Update file system permissions + * Update file permissions for a FusionPBX installation. + * + * This function updates the permissions of various directories in a FusionPBX installation, + * specifically adjusting ownership to match the expected behavior. The changes are only applied + * when running as root, and an error message is displayed otherwise. + * + * @param array $text A translation dictionary containing the label for when not running as root. + * @param settings $settings The current application settings instance. */ function update_file_permissions($text, settings $settings) { @@ -640,7 +646,14 @@ function update_file_permissions($text, settings $settings) { } /** - * Upgrade services + * Upgrade services by copying and enabling them in systemd. + * + * This function iterates through all service files found in the application's + * core and app directories, copies each one to /etc/systemd/system, reloads + * the daemon, and enables the service. + * + * @param string $text Text containing the upgrade description (not used) + * @param settings $settings Application settings */ function upgrade_services($text, settings $settings) { //echo ($text['description-upgrade_services'] ?? "")."\n"; @@ -657,7 +670,13 @@ function upgrade_services($text, settings $settings) { } /** - * Stop services + * Stops running services by name. + * + * This function iterates over all service files, extracts the service names, + * and stops each service using systemctl. + * + * @param array $text + * @param settings $settings */ function stop_services($text, settings $settings) { //echo ($text['description-stop_services'] ?? "")."\n"; @@ -672,7 +691,12 @@ function stop_services($text, settings $settings) { } /** - * Restart services + * Restarts all services + * + * This function restarts all core and app services. + * + * @param array $text Array containing localized text + * @param settings $settings Settings object */ function restart_services($text, settings $settings) { //echo ($text['description-restart_services'] ?? "")."\n"; @@ -687,8 +711,11 @@ function restart_services($text, settings $settings) { } /** - * Get the service name - * @param string $file + * Finds the service name in an INI file from a given file. + * + * @param string $file The fully qualified path and file containing the ExecStart command. + * + * @return string|null The service name if found, otherwise an empty string. */ function find_service_name(string $file) { $parsed = parse_ini_file($file); @@ -703,9 +730,9 @@ function find_service_name(string $file) { } /** - * Checks if the current user has root privileges. + * Checks whether the current user is the root user or not. * - * @return bool Returns true if the current user is the root user, false otherwise. + * @return bool True if the current user has root privileges, false otherwise. */ function is_root(): bool { return posix_getuid() === 0; diff --git a/core/upgrade/upgrade_menu.php b/core/upgrade/upgrade_menu.php index 61c7834945..c6f0ba0b70 100644 --- a/core/upgrade/upgrade_menu.php +++ b/core/upgrade/upgrade_menu.php @@ -52,9 +52,18 @@ $display_type = 'text'; show_upgrade_menu(); /** - * Show upgrade menu - * @global type $text - * @global type $software_name + * Display the upgrade menu to the user. + * + * This function displays a menu with various upgrade options and prompts the + * user for input. Based on the user's selection, it performs the corresponding + * actions such as upgrading code, schema, auto loader, domains, menu, + * permissions, file permissions, services, or restarting services. + * + * @return void + * + * @global text $text + * @global string $software_name + * @global settings $settings */ function show_upgrade_menu() { //set the global variables @@ -90,7 +99,7 @@ function show_upgrade_menu() { //show the command menu echo "Options:\n"; - foreach ($options as list($key, $label, $description)) { + foreach ($options as [$key, $label, $description]) { if (!is_numeric($key)) { echo " "; } echo " $key) $label" . ((!empty($option) && $option == 'h') ? " - " . $description : "") . "\n"; } @@ -172,8 +181,12 @@ function show_upgrade_menu() { } /** - * Rebuild the cache file - * @global type $text + * Upgrade auto loader by removing temporary files and updating it. + * + * @return void + * + * @global text $text + * @global auto_loader $autoload */ function do_upgrade_auto_loader() { global $text, $autoload; @@ -188,7 +201,10 @@ function do_upgrade_auto_loader() { } /** - * Update file system permissions + * Update file permissions for the application. + * + * @param array $text Array of text to display to the user. + * @param settings $settings Settings object containing various configuration options. */ function do_file_permissions($text, settings $settings) { @@ -256,18 +272,33 @@ function do_file_permissions($text, settings $settings) { } } +/** + * Returns the name of the currently logged in user. + * + * @return string|null The username of the current user, or null if not available + */ function current_user(): ?string { return posix_getpwuid(posix_getuid())['name'] ?? null; } //show the upgrade type +/** + * Returns a string containing the current version of the software. + * + * @return string|null The software version as a string, or null if not available. + */ function show_software_version(): ?string { return software::version() . "\n"; } /** - * Upgrade the source folder - * @return type + * Upgrade code by pulling the latest changes from version control. + * + * If the pull operation is successful, no result message will be returned. + * Otherwise, a result array containing 'result' set to false and a 'message' + * detailing the failure will be returned. + * + * @return null A result array or null on success */ function do_upgrade_code() { //assume failed @@ -284,8 +315,7 @@ function do_upgrade_code() { } /** - * Upgrade any of the git submodules - * @global type $text + * Upgrade code submodules by pulling the latest changes from Git repositories. */ function do_upgrade_code_submodules() { global $text; @@ -312,7 +342,7 @@ function do_upgrade_code_submodules() { } /** - * Execute all app_defaults.php files + * Perform upgrade on domains. */ function do_upgrade_domains() { $domain = new domains; @@ -320,7 +350,11 @@ function do_upgrade_domains() { } /** - * Upgrade schema and/or data_types + * Upgrades the database schema to the latest version. + * + * @param bool $data_types Whether or not to include data types in the upgrade process. Defaults to false. + * + * @return void */ function do_upgrade_schema(bool $data_types = false) { //get the database schema put it into an array then compare and update the database as needed. @@ -330,7 +364,9 @@ function do_upgrade_schema(bool $data_types = false) { } /** - * Restore the default menu + * Upgrades the menu and restores it to its default state. + * + * @return void */ function do_upgrade_menu() { //define the global variables @@ -365,7 +401,9 @@ function do_upgrade_menu() { } /** - * Restore the default permissions + * Upgrades database permissions to the latest version. + * + * @return void */ function do_upgrade_permissions() { //define the global variables @@ -381,7 +419,10 @@ function do_upgrade_permissions() { } /** - * Default upgrade schema and app defaults + * Performs default upgrades to the application, including multi-lingual support, + * database schema updates, and running of app_defaults.php files. + * + * @return void */ function do_upgrade_defaults() { //add multi-lingual support @@ -406,7 +447,14 @@ function do_upgrade_defaults() { } /** - * Upgrade services + * Upgrades the services to the latest version. + * + * This function upgrades all service files and enables them as systemd services. + * + * @param string $text An array containing upgrade information. The 'description-upgrade_services' key is used for informational messages. + * @param settings $settings Configuration settings object. + * + * @return void */ function do_upgrade_services($text, settings $settings) { echo ($text['description-upgrade_services'] ?? "")."\n"; @@ -423,8 +471,11 @@ function do_upgrade_services($text, settings $settings) { } /** - * Get the service name - * @param string $file + * Retrieves the name of a service from an .ini file. + * + * @param string $file Path to the .ini file containing service information. + * + * @return string The name of the service, or empty string if not found. */ function get_service_name(string $file) { $parsed = parse_ini_file($file); @@ -438,19 +489,22 @@ function get_service_name(string $file) { return ''; } - /** - * Checks if the current user has root privileges. + * Checks if the current user is the root user. * - * @return bool Returns true if the current user is the root user, false otherwise. + * @return bool True if the user is the root user, false otherwise. */ function is_root_user(): bool { return posix_getuid() === 0; } - /** - * Restart services + * Restarts services defined in the system. + * + * @param array $text An array of strings for service descriptions. + * @param object $settings An instance of the settings class, not used in this function. + * + * @return void */ function do_restart_services($text, settings $settings) { echo ($text['description-restart_services'] ?? "")."\n"; @@ -465,8 +519,13 @@ function do_restart_services($text, settings $settings) { } /** - * Load the old config.php file - * @return type + * Loads configuration from a PHP file and writes it to a new configuration file. + * + * If the configuration file does not exist but the config.php file is present, + * the settings in the config.php file are used as defaults for the new + * configuration file. The config directory is created if it does not exist. + * + * @return void */ function load_config_php() { //if the config file doesn't exist and the config.php does exist use it to write a new config file diff --git a/core/user_logs/resources/classes/user_logs.php b/core/user_logs/resources/classes/user_logs.php index 6fedd34916..a90f4304ec 100644 --- a/core/user_logs/resources/classes/user_logs.php +++ b/core/user_logs/resources/classes/user_logs.php @@ -27,145 +27,163 @@ /** * user_logs class */ - class user_logs { +class user_logs { - /** - * declare constant variables - */ - const app_name = 'user_logs'; - const app_uuid = '582a13cf-7d75-4ea3-b2d9-60914352d76e'; + /** + * declare constant variables + */ + const app_name = 'user_logs'; + const app_uuid = '582a13cf-7d75-4ea3-b2d9-60914352d76e'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $location; + /** + * declare private variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $location; + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //assign the variables + $this->name = 'user_log'; + $this->table = 'user_logs'; + $this->toggle_field = ''; + $this->toggle_values = ['true', 'false']; + $this->location = 'user_logs.php'; + } - //assign the variables - $this->name = 'user_log'; - $this->table = 'user_logs'; - $this->toggle_field = ''; - $this->toggle_values = ['true','false']; - $this->location = 'user_logs.php'; + /** + * Adds a new log entry to the database. + * + * This method creates a database object, prepares an array of data for insertion, + * saves the data, and removes any temporary permissions created during the process. + * + * @param array $result An associative array containing user login result details. + * @param string $details Optional additional details for failed logins. Defaults to ''. + */ + public static function add($result, $details = '') { + + //create the database object + $database = database::new(); + + //prepare the array + $array = []; + $array['user_logs'][0]["timestamp"] = 'now()'; + $array['user_logs'][0]["domain_uuid"] = $result['domain_uuid']; + $array['user_logs'][0]["user_uuid"] = $result['user_uuid']; + $array['user_logs'][0]["username"] = $result['username']; + $array['user_logs'][0]["hostname"] = gethostname(); + $array['user_logs'][0]["type"] = 'login'; + $array['user_logs'][0]["remote_address"] = $_SERVER['REMOTE_ADDR']; + $array['user_logs'][0]["user_agent"] = $_SERVER['HTTP_USER_AGENT']; + $array['user_logs'][0]["session_id"] = session_id(); + $array['user_logs'][0]["type"] = 'login'; + if ($result["authorized"]) { + $array['user_logs'][0]["result"] = 'success'; + } else { + $array['user_logs'][0]["result"] = 'failure'; + $array['user_logs'][0]["detail"] = $details; } - /** - * add user_logs - */ - public static function add($result, $details = '') { + //add the dialplan permission + $p = permissions::new(); + $p->add("user_log_add", 'temp'); - //create the database object - $database = database::new(); + //save to the data + $database->save($array, false); + $message = $database->message; - //prepare the array - $array = []; - $array['user_logs'][0]["timestamp"] = 'now()'; - $array['user_logs'][0]["domain_uuid"] = $result['domain_uuid']; - $array['user_logs'][0]["user_uuid"] = $result['user_uuid']; - $array['user_logs'][0]["username"] = $result['username']; - $array['user_logs'][0]["hostname"] = gethostname(); - $array['user_logs'][0]["type"] = 'login'; - $array['user_logs'][0]["remote_address"] = $_SERVER['REMOTE_ADDR']; - $array['user_logs'][0]["user_agent"] = $_SERVER['HTTP_USER_AGENT']; - $array['user_logs'][0]["session_id"] = session_id(); - $array['user_logs'][0]["type"] = 'login'; - if ($result["authorized"]) { - $array['user_logs'][0]["result"] = 'success'; - } - else { - $array['user_logs'][0]["result"] = 'failure'; - $array['user_logs'][0]["detail"] = $details; - } + //remove the temporary permission + $p->delete("user_log_add", 'temp'); + } - //add the dialplan permission - $p = permissions::new(); - $p->add("user_log_add", 'temp'); + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { - //save to the data - $database->save($array, false); - $message = $database->message; + //add multi-lingual support + $language = new text; + $text = $language->get(); - //remove the temporary permission - $p->delete("user_log_add", 'temp'); - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } + //increment the id + $x++; + } - //increment the id - $x++; - } + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //set message + message::add($text['message-delete']); + } + unset($records); } } - } + +} diff --git a/core/user_settings/resources/classes/user_settings.php b/core/user_settings/resources/classes/user_settings.php index 8aed87cda2..a20747de56 100644 --- a/core/user_settings/resources/classes/user_settings.php +++ b/core/user_settings/resources/classes/user_settings.php @@ -25,176 +25,196 @@ */ //define the user settings class - class user_settings { +class user_settings { - /** - * declare constant variables - */ - const app_name = 'user_settings'; - const app_uuid = '3a3337f7-78d1-23e3-0cfd-f14499b8ed97'; + /** + * declare constant variables + */ + const app_name = 'user_settings'; + const app_uuid = '3a3337f7-78d1-23e3-0cfd-f14499b8ed97'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * declare public variables - */ - public $user_uuid; + /** + * declare public variables + */ + public $user_uuid; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign private variables - $this->permission_prefix = 'user_setting_'; - $this->list_page = PROJECT_PATH."/core/user/user_edit.php?id=".urlencode($this->user_uuid ?? ''); - $this->table = 'user_settings'; - $this->uuid_prefix = 'user_setting_'; - $this->toggle_field = 'user_setting_enabled'; - $this->toggle_values = ['true','false']; - } + //assign private variables + $this->permission_prefix = 'user_setting_'; + $this->list_page = PROJECT_PATH . "/core/user/user_edit.php?id=" . urlencode($this->user_uuid ?? ''); + $this->table = 'user_settings'; + $this->uuid_prefix = 'user_setting_'; + $this->toggle_field = 'user_setting_enabled'; + $this->toggle_values = ['true', 'false']; + } - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate('/core/user_settings/user_settings.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //validate the token + $token = new token; + if (!$token->validate('/core/user_settings/user_settings.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; } + } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - //build the delete array - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } + //execute delete + $this->database->delete($array); + unset($array); - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //set message + message::add($text['message-delete']); + } + unset($records); } } + } - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/core/user_settings/user_settings.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - if (is_array($states) && @sizeof($states) != 0) { - $x = 0; - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } + //add multi-lingual support + $language = new text; + $text = $language->get(); + //validate the token + $token = new token; + if (!$token->validate('/core/user_settings/user_settings.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - } //method - } //class + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + if (is_array($states) && @sizeof($states) != 0) { + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } //method + +} //class diff --git a/core/users/resources/classes/users.php b/core/users/resources/classes/users.php index fccfeb926d..57f13c8099 100644 --- a/core/users/resources/classes/users.php +++ b/core/users/resources/classes/users.php @@ -27,309 +27,336 @@ /** * users class */ - class users { +class users { - /** - * declare constant variables - */ - const app_name = 'users'; - const app_uuid = '112124b3-95c2-5352-7e9d-d14c0b88f207'; + /** + * declare constant variables + */ + const app_name = 'users'; + const app_uuid = '112124b3-95c2-5352-7e9d-d14c0b88f207'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare the variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $location; + /** + * declare the variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $location; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Constructor for the class. + * + * This method initializes the object with setting_array and session data. + * + * @param array $setting_array An optional array of settings to override default values. Defaults to []. + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign the variables - $this->name = 'user'; - $this->table = 'users'; - $this->toggle_field = 'user_enabled'; - $this->toggle_values = ['true','false']; - $this->location = 'users.php'; - } + //assign the variables + $this->name = 'user'; + $this->table = 'users'; + $this->toggle_field = 'user_enabled'; + $this->toggle_values = ['true', 'false']; + $this->location = 'users.php'; + } - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { + /** + * Deletes one or multiple records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - //get the user_uuid - $user_uuid = $record['uuid']; - - //get the user's domain from v_users - if (permission_exists('user_domain')) { - $sql = "select domain_uuid from v_users "; - $sql .= "where user_uuid = :user_uuid "; - $parameters['user_uuid'] = $user_uuid; - $domain_uuid = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - } - else { - $domain_uuid = $this->domain_uuid; - } - - //required to be a superadmin to delete a member of the superadmin group - $superadmin_list = superadmin_list(); - if (if_superadmin($superadmin_list, $user_uuid)) { - if (!if_group("superadmin")) { - //access denied - do not delete the user - header("Location: index.php"); - return; - } - } - - //delete the user settings - $array['user_settings'][$x]['user_uuid'] = $user_uuid; - $array['user_settings'][$x]['domain_uuid'] = $domain_uuid; - - //delete the groups the user is assigned to - $array['user_groups'][$x]['user_uuid'] = $user_uuid; - $array['user_groups'][$x]['domain_uuid'] = $domain_uuid; - - //delete the user - $array['users'][$x]['user_uuid'] = $user_uuid; - $array['users'][$x]['domain_uuid'] = $domain_uuid; - - //increment the id - $x++; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute - $p = permissions::new(); - $p->add('user_setting_delete', 'temp'); - $p->add('user_group_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - $p->delete('user_setting_delete', 'temp'); - $p->delete('user_group_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; } - } - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + //get the user_uuid + $user_uuid = $record['uuid']; - //add multi-lingual support - $language = new text; - $text = $language->get(); + //get the user's domain from v_users + if (permission_exists('user_domain')) { + $sql = "select domain_uuid from v_users "; + $sql .= "where user_uuid = :user_uuid "; + $parameters['user_uuid'] = $user_uuid; + $domain_uuid = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + } else { + $domain_uuid = $this->domain_uuid; + } - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //required to be a superadmin to delete a member of the superadmin group + $superadmin_list = superadmin_list(); + if (if_superadmin($superadmin_list, $user_uuid)) { + if (!if_group("superadmin")) { + //access denied - do not delete the user + header("Location: index.php"); + return; + } + } + + //delete the user settings + $array['user_settings'][$x]['user_uuid'] = $user_uuid; + $array['user_settings'][$x]['domain_uuid'] = $domain_uuid; + + //delete the groups the user is assigned to + $array['user_groups'][$x]['user_uuid'] = $user_uuid; + $array['user_groups'][$x]['domain_uuid'] = $domain_uuid; + + //delete the user + $array['users'][$x]['user_uuid'] = $user_uuid; + $array['users'][$x]['domain_uuid'] = $domain_uuid; + + //increment the id + $x++; } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create the array from existing data - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $x = 0; - foreach ($rows as $row) { - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //add copy to the description - $array[$this->table][$x][$this->name.'_uuid'] = uuid(); - $array[$this->table][$x]['username'] = $row['username'].'-'.$text['label-copy']; - - //increment the id - $x++; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //save the array - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); - } - } - } - - /** - * Remove old user log entries. Called the maintenance service application. - * @param settings $settings - * @return void - */ - public static function database_maintenance(settings $settings): void { - $database = $settings->database(); - $domains = maintenance_service::get_domains($database); - foreach ($domains as $domain_uuid => $domain_name) { - $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); - $retention_days = $domain_settings->get('users', 'database_retention_days', ''); - if (!empty($retention_days) && is_numeric($retention_days)) { - $sql = "delete from v_user_logs where timestamp < NOW() - INTERVAL '$retention_days days'"; - $sql.= " and domain_uuid = '$domain_uuid'"; - $database->execute($sql); - $code = $database->message['code'] ?? 0; - if ($code == 200) { - maintenance_service::log_write(self::class, "Successfully removed entries older than $retention_days", $domain_uuid); - } else { - $message = $database->message['message'] ?? "An unknown error has occurred"; - maintenance_service::log_write(self::class, "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); - } - } else { - maintenance_service::log_write(self::class, "Database retention days not set or not numeric", $domain_uuid); } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute + $p = permissions::new(); + $p->add('user_setting_delete', 'temp'); + $p->add('user_group_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + $p->delete('user_setting_delete', 'temp'); + $p->delete('user_group_delete', 'temp'); + + //set message + message::add($text['message-delete']); + } + unset($records); } } } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create the array from existing data + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $x = 0; + foreach ($rows as $row) { + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //add copy to the description + $array[$this->table][$x][$this->name . '_uuid'] = uuid(); + $array[$this->table][$x]['username'] = $row['username'] . '-' . $text['label-copy']; + + //increment the id + $x++; + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //save the array + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } + + /** + * Remove old user log entries. Called the maintenance service application. + * + * @param settings $settings + * + * @return void + */ + public static function database_maintenance(settings $settings): void { + $database = $settings->database(); + $domains = maintenance_service::get_domains($database); + foreach ($domains as $domain_uuid => $domain_name) { + $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + $retention_days = $domain_settings->get('users', 'database_retention_days', ''); + if (!empty($retention_days) && is_numeric($retention_days)) { + $sql = "delete from v_user_logs where timestamp < NOW() - INTERVAL '$retention_days days'"; + $sql .= " and domain_uuid = '$domain_uuid'"; + $database->execute($sql); + $code = $database->message['code'] ?? 0; + if ($code == 200) { + maintenance_service::log_write(self::class, "Successfully removed entries older than $retention_days", $domain_uuid); + } else { + $message = $database->message['message'] ?? "An unknown error has occurred"; + maintenance_service::log_write(self::class, "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); + } + } else { + maintenance_service::log_write(self::class, "Database retention days not set or not numeric", $domain_uuid); + } + } + } +} diff --git a/core/users/user_imports.php b/core/users/user_imports.php index de388542f0..bb571886ab 100644 --- a/core/users/user_imports.php +++ b/core/users/user_imports.php @@ -38,18 +38,6 @@ $language = new text; $text = $language->get(); -//built in str_getcsv requires PHP 5.3 or higher, this function can be used to reproduce the functionality but requires PHP 5.1.0 or higher - if (!function_exists('str_getcsv')) { - function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { - $fp = fopen("php://memory", 'r+'); - fputs($fp, $input); - rewind($fp); - $data = fgetcsv($fp, null, $delimiter, $enclosure); // $escape only got added in 5.3.0 - fclose($fp); - return $data; - } - } - //get the http get values and set them as php variables $action = $_POST["action"] ?? ''; $from_row = $_POST["from_row"] ?? ''; @@ -220,6 +208,14 @@ } //get the parent table + /** + * Retrieves the parent table of a given table in the schema. + * + * @param array $schema An array containing schema information, where each row represents a table. + * @param string $table_name The name of the table for which to retrieve the parent. + * + * @return mixed|null The parent table of the specified table, or null if no match is found. + */ function get_parent($schema,$table_name) { foreach ($schema as $row) { if ($row['table'] == $table_name) { diff --git a/core/websockets/resources/classes/base_message.php b/core/websockets/resources/classes/base_message.php index 4ea95f079b..ee3224ea1e 100644 --- a/core/websockets/resources/classes/base_message.php +++ b/core/websockets/resources/classes/base_message.php @@ -29,19 +29,22 @@ /** * A base message for communication * + * @param string $payload ; + * * @author Tim Fry - * @param string $payload; */ class base_message { /** * The id is contained to the base_message class. Subclasses or child classes should not adjust this value + * * @var int */ private $id; /** * Payload can be any value + * * @var mixed */ protected $payload; @@ -51,6 +54,7 @@ class base_message { * When the array is provided as an associative array, the object properties * are filled using the array key as the property name and the value of the array * for the value of the property in the object. + * * @param array $associative_properties_array */ public function __construct($associative_properties_array = []) { @@ -69,7 +73,9 @@ class base_message { * If the method exists then the method will be called to get the value in the object property. * If the method is not in the object then the property name is checked to see if it is valid. If the * name is not available then an exception is thrown. + * * @param string $name Name of the property + * * @return mixed * @throws InvalidProperty */ @@ -90,13 +96,15 @@ class base_message { /** * Sets the object property in the given name to be the given value - * @param string $name Name of the object property - * @param mixed $value Value of the object property + * + * @param string $name Name of the object property + * @param mixed $value Value of the object property + * * @return void * @throws \InvalidArgumentException */ public function __set(string $name, $value): void { - if (method_exists($this, "set_$name")){ + if (method_exists($this, "set_$name")) { // // By calling the method with the setter name of the property first, we give // the child object the opportunity to modify the value before it is @@ -124,6 +132,7 @@ class base_message { /** * Provides a method that PHP will call if the object is echoed or printed. + * * @return string JSON string representing the object * @depends to_json */ @@ -133,6 +142,7 @@ class base_message { /** * Returns this object ID given by PHP + * * @return int */ public function get_id(): int { @@ -141,7 +151,9 @@ class base_message { /** * Sets the message payload to be delivered + * * @param mixed $payload Payload for the message to carry + * * @return $this Returns this object for chaining */ public function set_payload($payload) { @@ -151,6 +163,7 @@ class base_message { /** * Returns the payload contained in this message + * * @return mixed Payload in the message */ public function get_payload() { @@ -164,8 +177,11 @@ class base_message { * the method is called with no parameters given, the payload is * returned to the caller. * Payload the message object is delivering + * * @param mixed $payload If set, payload is set to the value. Otherwise, the payload is returned. - * @return mixed If payload was given to call the method, this object is returned. If no value was provided the payload is returned. + * + * @return mixed If payload was given to call the method, this object is returned. If no value was provided the + * payload is returned. * @see set_payload * @see get_payload */ @@ -178,7 +194,9 @@ class base_message { /** * Recursively convert this object or child object to an array. + * * @param mixed $iterate Private value to be set while iterating over the object properties + * * @return array Array representing the properties of this object */ public function to_array($iterate = null): array { @@ -191,7 +209,7 @@ class base_message { $value = $this->to_array($value); } elseif (is_object($value) && method_exists($value, 'to_array')) { $value = $value->to_array(); - } elseif (is_object($value) && method_exists($value, '__toArray')) { // PHP array casting + } elseif (is_object($value) && method_exists($value, '__toArray')) { // PHP array casting $value = $value->__toArray(); } $array[$property] = $value; @@ -201,6 +219,7 @@ class base_message { /** * Returns a json string + * * @return string * @depends to_array */ @@ -210,6 +229,7 @@ class base_message { /** * Returns an array representing this object or child object. + * * @return array Array of object properties */ public function __toArray(): array { diff --git a/core/websockets/resources/classes/base_websocket_system_service.php b/core/websockets/resources/classes/base_websocket_system_service.php index 195d5a2de1..426044d04c 100644 --- a/core/websockets/resources/classes/base_websocket_system_service.php +++ b/core/websockets/resources/classes/base_websocket_system_service.php @@ -1,7 +1,7 @@ */ @@ -12,12 +12,14 @@ abstract class base_websocket_system_service extends service implements websocke /** * Sets a time to fire the on_timer function + * * @var int|null */ protected $timer_expire_time = null; /** * Websocket client + * * @var websocket_client $ws_client */ protected $ws_client; @@ -26,6 +28,7 @@ abstract class base_websocket_system_service extends service implements websocke /** * Array of topics and their callbacks + * * @var array */ protected $topics; @@ -35,24 +38,37 @@ abstract class base_websocket_system_service extends service implements websocke * Listener is an array of socket and callback used to listen for events on the socket. When a listener is added, * the socket is added to the array of listeners. When the socket is closed, the listener is removed from the * array of listeners. When an event is received on the respective socket, the provided callback is called. + * * @var array */ protected $listeners; + /** + * Outputs the version of the Service. + * + * @return void + */ protected static function display_version(): void { echo "System Dashboard Service 1.0\n"; } /** * Set a timer to trigger the defined function every $seconds. To stop the timer, set the value to null + * * @param int $seconds + * * @return void * @see on_timer */ protected function set_timer(int $seconds, callable $callable): void { $this->timers[] = ['expire_time' => time() + $seconds, 'callable' => $callable]; - } + } + /** + * Append command options to set the websockets port and host address + * + * @return void + */ protected static function set_command_options() { parent::append_command_option( command_option::new() @@ -74,10 +90,20 @@ abstract class base_websocket_system_service extends service implements websocke ); } + /** + * Sets the port for the WebSocket connection. + * + * @param int $port The new port number to use for the WebSocket connection + */ protected static function set_websockets_port($port): void { self::$websocket_port = $port; } + /** + * Set the host address for websockets connections. + * + * @param string $host The host address to use for websockets connections + */ protected static function set_websockets_host_address($host): void { self::$websocket_host = $host; } @@ -85,14 +111,20 @@ abstract class base_websocket_system_service extends service implements websocke /** * Add a socket listener * - * @param $socket + * @param $socket * @param callable $callback + * * @return void */ protected function add_listener($socket, callable $callback): void { $this->listeners[] = [$socket, $callback]; } + /** + * Main execution loop for handling WebSocket events and timers. + * + * @return int Exit code, indicating whether the process exited normally (0) or with an error (1). + */ public function run(): int { // set the timers property as an array $this->timers = []; @@ -175,7 +207,7 @@ abstract class base_websocket_system_service extends service implements websocke // Timers can be set by child classes if (!empty($this->timers)) { // Check all timers - foreach($this->timers as $key => $array) { + foreach ($this->timers as $key => $array) { // Check if the timer should be run if (time() >= $array['expire_time']) { // Get the callback function @@ -197,6 +229,7 @@ abstract class base_websocket_system_service extends service implements websocke /** * Connects to the web socket server using a websocket_client object + * * @return bool True if connected and False if not able to connect */ protected function connect_to_ws_server(): bool { @@ -227,7 +260,7 @@ abstract class base_websocket_system_service extends service implements websocke /** * Handles the message from the web socket client and triggers the appropriate requested topic event - * @param resource $ws_client + * * @return void */ private function handle_websocket_event() { @@ -257,7 +290,8 @@ abstract class base_websocket_system_service extends service implements websocke /** * Call each of the registered events for the websocket topic that has arrived - * @param string $topic + * + * @param string $topic * @param websocket_message $websocket_message */ private function trigger_topic(string $topic, websocket_message $websocket_message) { @@ -272,6 +306,11 @@ abstract class base_websocket_system_service extends service implements websocke } } + /** + * Authenticate with the websocket server using a service token + * + * @param websocket_message $websocket_message The incoming websocket message that triggered this event + */ protected function on_authenticate(websocket_message $websocket_message) { $this->info("Authenticating with websocket server"); // Create a service token @@ -283,7 +322,8 @@ abstract class base_websocket_system_service extends service implements websocke /** * Allows the service to register a callback so when the topic arrives the callable is called - * @param string $topic + * + * @param string $topic * @param callable $callable */ protected function on_topic($topic, $callable) { @@ -293,9 +333,19 @@ abstract class base_websocket_system_service extends service implements websocke $this->topics[$topic][] = $callable; } + /** + * Send a websocket message to the client + * + * @param websocket_message $websocket_message The message to be sent + */ protected function respond(websocket_message $websocket_message): void { websocket_client::send($this->ws_client->socket(), $websocket_message); } + /** + * Register topics and associated callbacks. + * + * @return void + */ abstract protected function register_topics(): void; } diff --git a/core/websockets/resources/classes/permission_filter.php b/core/websockets/resources/classes/permission_filter.php index b1736a38ba..e7f65fe77e 100644 --- a/core/websockets/resources/classes/permission_filter.php +++ b/core/websockets/resources/classes/permission_filter.php @@ -36,11 +36,25 @@ class permission_filter implements filter { private $field_map; private $permissions; + /** + * Initializes a new instance of this class with a map of event field keys to permissions and an optional list of + * additional permissions. + * + * @param array $event_field_key_to_permission_map Map of event field keys to permissions + * @param array $permissions Optional list of additional permissions (default: []) + */ public function __construct(array $event_field_key_to_permission_map, array $permissions = []) { $this->field_map = $event_field_key_to_permission_map; $this->add_permissions($permissions); } + /** + * Invokes the object to check if a value can be set for a given field. + * + * @param string $key The key of the field to check + * + * @return bool|null True if the value can be set, null otherwise + */ public function __invoke(string $key, $value): ?bool { $permission = $this->field_map[$key] ?? null; if ($permission === null || $this->has_permission($permission)) { @@ -50,7 +64,9 @@ class permission_filter implements filter { } /** - * Adds an associative array of permissions where $key is the name of the permission and $value is ignored as it should always be set to true. + * Adds an associative array of permissions where $key is the name of the permission and $value is ignored as it + * should always be set to true. + * * @param array $permissions */ public function add_permissions(array $permissions) { @@ -62,6 +78,7 @@ class permission_filter implements filter { /** * Adds a single permission + * * @param string $key */ public function add_permission(string $key) { @@ -70,7 +87,9 @@ class permission_filter implements filter { /** * Checks if the filter has a permission + * * @param string $key + * * @return bool */ public function has_permission(string $key): bool { diff --git a/core/websockets/resources/classes/socket_exception.php b/core/websockets/resources/classes/socket_exception.php index 46d05860b3..792f4402d5 100644 --- a/core/websockets/resources/classes/socket_exception.php +++ b/core/websockets/resources/classes/socket_exception.php @@ -33,6 +33,17 @@ */ class socket_exception extends \Exception { public $id; + + /** + * Initializes a new instance of the object. + * + * @param mixed $id Unique identifier for this exception (default: null) + * @param string $message Exception message (default: "") + * @param int $code Exception code (default: 0) + * @param \Throwable|null $previous The previous exception (default: null) + * + * @return void + */ public function __construct($id = null, string $message = "", int $code = 0, ?\Throwable $previous = null) { $this->id = $id; return parent::__construct($message, $code, $previous); diff --git a/core/websockets/resources/classes/subscriber.php b/core/websockets/resources/classes/subscriber.php index 21a395774b..4389b5a3af 100644 --- a/core/websockets/resources/classes/subscriber.php +++ b/core/websockets/resources/classes/subscriber.php @@ -30,12 +30,14 @@ declare(strict_types=1); /** * Description of subscriber + * * @author Tim Fry */ class subscriber { /** * The ID of the object given by PHP + * * @var spl_object_id */ private $id; @@ -51,128 +53,151 @@ class subscriber { * The resource is cast to an integer and then saved in order to match the * a resource to the original socket. This is primarily used in the equals * method to test for equality. + * * @var int */ private $socket_id; /** * Remote IP of the socket resource connection + * * @var string */ private $remote_ip; /** * Remote port of the socket resource connection + * * @var int */ private $remote_port; /** * Services the subscriber has subscribed to + * * @var array */ private $services; /** * Permissions array of the subscriber + * * @var array */ private $permissions; /** * Domain name the subscriber belongs to + * * @var string|null */ private $domain_name; /** * Domain UUID the subscriber belongs to + * * @var string|null */ private $domain_uuid; /** * Token hash used to validate this subscriber + * * @var string|null */ private $token_hash; /** * Token name used to validate this subscriber + * * @var string|null */ private $token_name; /** * Epoch time the token was issued + * * @var int */ private $token_time; /** * Time limit in seconds + * * @var int */ private $token_limit; /** * Whether the subscriber has a time limit set for their token or not + * * @var bool True when there is a time limit. False if no time limit set. */ private $enable_token_time_limit; /** * Whether the subscriber is able to broadcast messages as a service + * * @var bool */ private $service; /** * The name of the service class object to handle callbacks + * * @var string|null */ private $service_class; /** * If the subscriber is a service the service name used + * * @var string|null */ private $service_name; /** * The filter used to send web socket messages + * * @var filter */ private $filter; /** * Function or method name to call when sending information through the socket + * * @var callable */ private $callback; /** * Subscriptions to services + * * @var array */ private $subscriptions; /** * Whether or not this subscriber has been authenticated + * * @var bool */ private $authenticated; /** * User information + * * @var array */ private $user; /** * Creates a subscriber object. - * @param resource|stream $socket Connected socket - * @param callable $frame_wrapper The callback used to wrap communication in a web socket frame. Sending NULL to the frame wrapper should send a disconnect. + * + * @param resource|stream $socket Connected socket + * @param callable $frame_wrapper The callback used to wrap communication in a web socket frame. Sending + * NULL to the frame wrapper should send a disconnect. + * * @throws \socket_exception Thrown when the passed socket is already closed * @throws \InvalidArgumentException Thrown when the $callback is not a valid callback */ @@ -186,9 +211,9 @@ class subscriber { } // set object identifiers - $this->id = md5(spl_object_hash($this)); // PHP unique object hash is similar to 000000000000000f0000000000000000 so we use md5 - $this->socket = $socket; - $this->socket_id = (int) $socket; + $this->id = md5(spl_object_hash($this)); // PHP unique object hash is similar to 000000000000000f0000000000000000 so we use md5 + $this->socket = $socket; + $this->socket_id = (int)$socket; $this->domain_name = ''; $this->domain_uuid = ''; @@ -197,14 +222,14 @@ class subscriber { [$this->remote_ip, $this->remote_port] = self::get_remote_information_from_socket($socket); // set defaults - $this->authenticated = false; - $this->permissions = []; - $this->services = []; + $this->authenticated = false; + $this->permissions = []; + $this->services = []; $this->enable_token_time_limit = false; - $this->subscriptions = []; - $this->service = false; - $this->service_name = ''; - $this->user = []; + $this->subscriptions = []; + $this->service = false; + $this->service_name = ''; + $this->user = []; // Save the websocket frame wrapper used to communicate to this subscriber $this->callback = $frame_wrapper; @@ -215,6 +240,7 @@ class subscriber { /** * Returns the user array information in this subscriber + * * @return array */ public function get_user_array(): array { @@ -222,18 +248,23 @@ class subscriber { } /** - * Returns the user information from the provided key. - * @param string $key - * @return mixed + * Retrieves a user setting by its key. + * + * @param string $key The name of the user setting to retrieve + * @param mixed $default_value The default value to return if the setting is not found (optional) + * + * @return mixed The value of the user setting, or the default value if it does not exist */ public function get_user_setting($key, $default_value = null) { return $this->user[$key] ?? $default_value; } /** - * Gets or sets the subscribed to services - * @param array $services - * @return $this|array + * Checks if this subscriber is subscribed to the given services + * + * @param array $services Optional list of service names, e.g. [active.calls, inactive.calls] + * + * @return mixed This object or an array of subscribed service names */ public function subscribed_to($services = []) { if (func_num_args() > 0) { @@ -245,7 +276,9 @@ class subscriber { /** * Gets or sets the service class name for this subscriber - * @param string $service_class + * + * @param ?string $service_class + * * @return $this|string */ public function service_class($service_class = null) { @@ -258,7 +291,9 @@ class subscriber { /** * Sets the filter used for this subscriber + * * @param filter $filter + * * @return $this */ public function set_filter(filter $filter) { @@ -268,6 +303,7 @@ class subscriber { /** * Returns the filter used for this subscriber + * * @return filter */ public function get_filter() { @@ -284,6 +320,7 @@ class subscriber { /** * Disconnects the socket resource used for this subscriber + * * @return bool true on success and false on failure */ public function disconnect(): bool { @@ -298,9 +335,11 @@ class subscriber { } /** - * Compares the current object with another object to see if they are exactly the same object - * @param subscriber|resource $object_or_resource_or_id - * @return bool + * Checks if this subscriber is equal to the given object, resource or id. + * + * @param mixed $object_or_resource_or_id The object, resource or id to compare with + * + * @return bool True if the subscribers are equal, false otherwise */ public function equals($object_or_resource_or_id): bool { // Compare by resource @@ -322,7 +361,9 @@ class subscriber { /** * Compares this object to another object or resource id. - * @param type $object_or_resource + * + * @param $object_or_resource The object or resource to compare + * * @return bool True if this object is not equal to the other object or resource. False otherwise. * @see subscriber::equals() */ @@ -332,9 +373,10 @@ class subscriber { /** * Allow accessing copies of the private values to ensure the object values are immutable. - * @param string $name - * @return mixed - * @throws \InvalidArgumentException + * + * @param string $name The name of the attribute to be accessed + * + * @throws \InvalidArgumentException If the attribute does not exist or direct access is prohibited */ public function __get(string $name) { switch ($name) { @@ -357,6 +399,7 @@ class subscriber { /** * Returns the current ID of this subscriber. * The ID is set in the constructor using the spl_object_id given by PHP + * * @return string */ public function id(): string { @@ -365,7 +408,9 @@ class subscriber { /** * Checks if this subscriber has the permission given in $permission - * @param string $permission + * + * @param string $permission The permission to check + * * @return bool True when this subscriber has the permission and false otherwise */ public function has_permission(string $permission): bool { @@ -378,6 +423,7 @@ class subscriber { /** * Returns the array of permissions this subscriber has been assigned. + * * @return array */ public function get_permissions(): array { @@ -388,6 +434,7 @@ class subscriber { * Returns the domain name used. *

Note:
* This value is not validated in the object and must be validated.

+ * * @return string */ public function get_domain_name(): string { @@ -395,8 +442,9 @@ class subscriber { } /** - * Returns the current socket resource used to communicate with this subscriber - * @return resource|stream Resource Id or stream used + * Returns the associated socket + * + * @return resource */ public function socket() { return $this->socket; @@ -404,6 +452,7 @@ class subscriber { /** * Returns the socket ID that was cast to an integer when the object was created. + * * @return int The socket ID cast as an integer. */ public function socket_id(): int { @@ -412,7 +461,9 @@ class subscriber { /** * Validates the given token against the loaded token in the this subscriber + * * @param array $token Must be an associative array with name and hash as the keys. + * * @return bool */ public function is_valid_token(array $token): bool { @@ -456,7 +507,9 @@ class subscriber { * Validates the given token array against the token previously saved in the file system. When the token is valid * the token will be saved in this object and the file removed. This method should not be called a second time * once a token has be authenticated. + * * @param array $request_token + * * @return bool */ public function authenticate_token(array $request_token): bool { @@ -486,9 +539,9 @@ class subscriber { $array = include($token_file); // Assign to local variables to reflect local storage - $token_name = $array['token']['name'] ?? ''; - $token_hash = $array['token']['hash'] ?? ''; - $token_time = intval($array['token']['time'] ?? 0); + $token_name = $array['token']['name'] ?? ''; + $token_hash = $array['token']['hash'] ?? ''; + $token_time = intval($array['token']['time'] ?? 0); $token_limit = intval($array['token']['limit'] ?? 0); // Compare the token given in the request with the one that was in local storage @@ -504,11 +557,11 @@ class subscriber { if ($valid) { // Store the valid token information in this object - $this->token_name = $token_name; - $this->token_hash = $token_hash; - $this->token_time = $token_time; + $this->token_name = $token_name; + $this->token_hash = $token_hash; + $this->token_time = $token_time; $this->enable_token_time_limit = $token_limit > 0; - $this->token_limit = $token_limit * 60; // convert to seconds for time() comparison + $this->token_limit = $token_limit * 60; // convert to seconds for time() comparison // Add the domain $this->domain_name = $array['domain']['name'] ?? ''; @@ -534,7 +587,7 @@ class subscriber { // // Set the service information in the object // - $this->service_name = "" . ($array['service_name'] ?? ''); + $this->service_name = "" . ($array['service_name'] ?? ''); $this->service_class = "" . ($array['service_class'] ?? ''); // @@ -565,6 +618,7 @@ class subscriber { /** * Returns whether or not this subscriber has been authenticated. + * * @return bool */ public function is_authenticated(): bool { @@ -573,7 +627,9 @@ class subscriber { /** * Allows overriding the token authentication + * * @param bool $authenticated + * * @return self */ public function set_authenticated(bool $authenticated): self { @@ -583,12 +639,14 @@ class subscriber { /** * Sets the domain UUID and name + * * @param string $uuid * @param string $name + * * @return self * @throws invalid_uuid_exception * @depends is_uuid() - * @see is_uuid() + * @see is_uuid() */ public function set_domain(string $uuid, string $name): self { if (is_uuid($uuid)) { @@ -602,6 +660,7 @@ class subscriber { /** * Returns whether or not this subscriber is a service. + * * @return bool True if this subscriber is a service and false if this subscriber is not a service. */ public function is_service(): bool { @@ -610,6 +669,7 @@ class subscriber { /** * Alias of service_name without the parameters + * * @return string */ public function get_service_name(): string { @@ -618,7 +678,9 @@ class subscriber { /** * Get or set the service_name + * * @param string|null $service_name + * * @return string|$this */ public function service_name($service_name = null) { /* : string|self */ @@ -631,7 +693,9 @@ class subscriber { /** * Returns whether or not the service name matches this subscriber + * * @param string $service_name Name of the service + * * @return bool True if this subscriber matches the provided service name. False if this subscriber does not * match or this subscriber is not a service. */ @@ -641,6 +705,7 @@ class subscriber { /** * Returns true if the socket/stream is still open (not at EOF). + * * @return bool Returns true if connected and false if the connection has closed */ public function is_connected(): bool { @@ -649,6 +714,7 @@ class subscriber { /** * Returns true if the subscriber is no longer connected + * * @return bool Returns true if the subscriber is no longer connected */ public function is_not_connected(): bool { @@ -657,7 +723,9 @@ class subscriber { /** * Checks if this subscriber is subscribed to the given service name + * * @param string $service_name The service name ie. active.calls + * * @return bool * @see subscriber::subscribe */ @@ -667,7 +735,9 @@ class subscriber { /** * Subscribe to a service by ensuring this subscriber has the appropriate permissions + * * @param string $service_name + * * @return self */ public function subscribe(string $service_name): self { @@ -677,7 +747,9 @@ class subscriber { /** * Sends a response to the subscriber using the provided callback web socket wrapper in the constructor + * * @param string $json Valid JSON response to send to the connected client + * * @throws subscriber_token_expired_exception Thrown when the time limit set in the token has expired */ public function send(string $json) { @@ -691,7 +763,9 @@ class subscriber { /** * Sends the given message through the websocket + * * @param websocket_message $message + * * @throws socket_disconnected_exception */ public function send_message(websocket_message $message) { @@ -716,17 +790,21 @@ class subscriber { throw new \socket_disconnected_exception($this->id); } - $this->send((string) $message); + $this->send((string)$message); return; } /** * The remote information is retrieved using the stream_socket_get_name function. + * * @param resource $socket - * @return array Returns a zero-based indexed array of first the IP address and then the port of the remote machine. - * @see stream_socket_get_name(); - * @link https://php.net/stream_socket_get_name PHP documentation for underlying function used to return information. + * + * @return array Returns a zero-based indexed array of first the IP address and then the port of the remote + * machine. + * @see stream_socket_get_name(); + * @link https://php.net/stream_socket_get_name PHP documentation for underlying function used to return + * information. */ public static function get_remote_information_from_socket($socket): array { return explode(':', stream_socket_get_name($socket, true), 2); @@ -734,10 +812,13 @@ class subscriber { /** * The remote information is retrieved using the stream_socket_get_name function. + * * @param resource $socket + * * @return string Returns the IP address of the remote machine or an empty string. - * @see stream_socket_get_name(); - * @link https://php.net/stream_socket_get_name PHP documentation for underlying function used to return information. + * @see stream_socket_get_name(); + * @link https://php.net/stream_socket_get_name PHP documentation for underlying function used to return + * information. */ public static function get_remote_ip_from_socket($socket): string { $array = explode(':', stream_socket_get_name($socket, true), 2); @@ -746,10 +827,13 @@ class subscriber { /** * The remote information is retrieved using the stream_socket_get_name function. + * * @param resource $socket + * * @return string Returns the port of the remote machine as a string or an empty string. - * @see stream_socket_get_name(); - * @link https://php.net/stream_socket_get_name PHP documentation for underlying function used to return information. + * @see stream_socket_get_name(); + * @link https://php.net/stream_socket_get_name PHP documentation for underlying function used to return + * information. */ public static function get_remote_port_from_socket($socket): string { $array = explode(':', stream_socket_get_name($socket, true), 2); @@ -760,10 +844,13 @@ class subscriber { * Returns the name and path for the token. * Priority is given to the /dev/shm folder if it exists as this is much faster. If that is not available, then the * sys_get_temp_dir() function is called to get a storage location. + * * @param string $token_name + * * @return string - * @see sys_get_temp_dir() - * @link https://php.net/sys_get_temp_dir PHP Documentation for the function used to get the temporary storage location. + * @see sys_get_temp_dir() + * @link https://php.net/sys_get_temp_dir PHP Documentation for the function used to get the temporary storage + * location. */ public static function get_token_file($token_name): string { // Try to store in RAM first @@ -787,9 +874,10 @@ class subscriber { * the web socket service may not yet have access to the token before the * web socket client requests authorization. * - * @param array $token Standard token issued from the token object - * @param array $services A simple array list of service names to subscribe to - * @param int $time_limit_in_minutes Set a token time limit. Setting to zero will disable the time limit + * @param array $token Standard token issued from the token object + * @param array $services A simple array list of service names to subscribe to + * @param int $time_limit_in_minutes Set a token time limit. Setting to zero will disable the time limit + * * @see token::create() */ public static function save_token(array $token, array $services, int $time_limit_in_minutes = 0) { @@ -813,7 +901,7 @@ class subscriber { // // Store the epoch time and time limit // - $array['token']['time'] = "" . time(); + $array['token']['time'] = "" . time(); $array['token']['limit'] = $time_limit_in_minutes; // @@ -839,6 +927,7 @@ class subscriber { /** * Checks the token time stored in this subscriber + * * @return bool True if the token has expired. False if the token is still valid */ public function token_time_exceeded(): bool { diff --git a/core/websockets/resources/classes/subscriber_exception.php b/core/websockets/resources/classes/subscriber_exception.php index 7359d0082c..9cd490d217 100644 --- a/core/websockets/resources/classes/subscriber_exception.php +++ b/core/websockets/resources/classes/subscriber_exception.php @@ -33,6 +33,17 @@ */ class subscriber_exception extends \Exception { public $subscriber_id; + + /** + * Initializes a new instance of the class. + * + * @param mixed $subscriber_id The subscriber's ID. + * @param string $message [optional] The exception message. Defaults to an empty string. + * @param int $code [optional] The user-defined errorCode integer. Defaults to 0. + * @param Throwable|null $previous [optional] The previous throwable that caused this one, or null if none. Defaults to null. + * + * @return void + */ public function __construct($subscriber_id, string $message = "", int $code = 0, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->subscriber_id = $subscriber_id; diff --git a/core/websockets/resources/classes/subscriber_missing_permission_exception.php b/core/websockets/resources/classes/subscriber_missing_permission_exception.php index b8fbd431a8..b7d4dde123 100644 --- a/core/websockets/resources/classes/subscriber_missing_permission_exception.php +++ b/core/websockets/resources/classes/subscriber_missing_permission_exception.php @@ -32,6 +32,16 @@ * @author Tim Fry */ class subscriber_missing_permission_exception extends \subscriber_exception { + /** + * Initializes the object with subscriber id and error message. + * + * @param string|int $subscriber_id Subscriber's unique identifier + * @param string $message [optional] Custom error message. Defaults to "Subscriber is missing required permission". + * @param int $code [optional] Error code. Defaults to 0. + * @param \Throwable|null $previous [optional] The previous exception. Defaults to null. + * + * @return void + */ public function __construct($subscriber_id, string $message = "Subscriber is missing required permission", int $code = 0, ?\Throwable $previous = null) { return parent::__construct($subscriber_id, $message, $code, $previous); } diff --git a/core/websockets/resources/classes/subscriber_not_subscribed_exception.php b/core/websockets/resources/classes/subscriber_not_subscribed_exception.php index f664995ad7..c72276be2e 100644 --- a/core/websockets/resources/classes/subscriber_not_subscribed_exception.php +++ b/core/websockets/resources/classes/subscriber_not_subscribed_exception.php @@ -32,6 +32,14 @@ * @author Tim Fry */ class subscriber_not_subscribed_exception extends subscriber_exception { + /** + * Initializes a new instance of the class with the specified subscriber ID and message. + * + * @param string|int $subscriber_id The identifier for the subscriber. + * @param string $message The error message. Defaults to "Subscriber is not subscribed". + * @param int $code The HTTP status code. Defaults to 0. + * @param \Throwable|null $previous The previous exception, if any. + */ public function __construct($subscriber_id, string $message = "Subscriber is not subscribed", int $code = 0, ?\Throwable $previous = null) { parent::__construct($subscriber_id, $message, $code, $previous); } diff --git a/core/websockets/resources/classes/subscriber_token_expired_exception.php b/core/websockets/resources/classes/subscriber_token_expired_exception.php index d0273d94dd..f68e6e3581 100644 --- a/core/websockets/resources/classes/subscriber_token_expired_exception.php +++ b/core/websockets/resources/classes/subscriber_token_expired_exception.php @@ -32,6 +32,19 @@ * @author Tim Fry */ class subscriber_token_expired_exception extends \subscriber_exception { + /** + * Constructor for the class. + * + * Initializes a new instance of the class with optional subscriber ID, message, + * code, and previous exception information. + * + * @param string|null $subscriber_id Optional subscriber ID. + * @param string $message The error message. Defaults to "Subscriber token expired". + * @param int $code The HTTP status code. Defaults to 0. + * @param \Throwable|null $previous The previous exception. Defaults to null. + * + * @return void + */ public function __construct($subscriber_id = null, string $message = "Subscriber token expired", int $code = 0, ?\Throwable $previous = null) { return parent::__construct($subscriber_id, $message, $code, $previous); } diff --git a/core/websockets/resources/classes/websocket_client.php b/core/websockets/resources/classes/websocket_client.php index 02a39fa039..22f8787954 100644 --- a/core/websockets/resources/classes/websocket_client.php +++ b/core/websockets/resources/classes/websocket_client.php @@ -58,10 +58,10 @@ class websocket_client { * Connects to the WebSocket server and performs handshake. */ public function connect(): void { - $parts = parse_url($this->url); - $this->host = $parts['host'] ?? ''; - $this->port = $parts['port'] ?? 80; - $this->path = $parts['path'] ?? '/'; + $parts = parse_url($this->url); + $this->host = $parts['host'] ?? ''; + $this->port = $parts['port'] ?? 80; + $this->path = $parts['path'] ?? '/'; $this->origin = ($parts['scheme'] ?? 'http') . '://' . $this->host; $this->resource = stream_socket_client("tcp://{$this->host}:{$this->port}", $errno, $errstr, 5); @@ -100,7 +100,7 @@ class websocket_client { if (!preg_match('/Sec-WebSocket-Accept: (.*)\r\n/', $response, $m)) { throw new \RuntimeException("Handshake failed: no Accept header"); } - $accept = trim($m[1]); + $accept = trim($m[1]); $expected = base64_encode(sha1($this->key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); if ($accept !== $expected) { throw new \RuntimeException("Handshake failed: invalid Accept key"); @@ -112,19 +112,47 @@ class websocket_client { } } + /** + * Sets the blocking mode of the underlying socket. + * + * @param bool $block If true, sets the socket to block on read/write operations; otherwise, sets it to non-blocking. + * + * @return void + */ public function set_blocking(bool $block) { if ($this->is_connected()) stream_set_blocking($this->resource, $block); } + /** + * Sets the file descriptor to be in blocking mode. + * + * This ensures that any write operations on this socket will block until the entire data has been sent. + * + * @return void + */ public function block() { $this->set_blocking(true); } + /** + * Disables blocking mode for this resource. + * + * This method sets the resource to non-blocking mode, allowing I/O operations to complete immediately + * without waiting for completion. If an operation is attempted while in non-blocking mode and no data + * is available, a BlockingQueueException will be raised. + * + * @return void + */ public function unblock() { $this->set_blocking(false); } + /** + * Checks if the underlying socket is in a non-blocking state. + * + * @return bool True if the socket is blocking, false otherwise. + */ public function is_blocking(): bool { if ($this->is_connected()) { // @@ -141,7 +169,9 @@ class websocket_client { } /** - * Returns true if socket is connected. + * Checks if a connection to the web socket server is established and active. + * + * @return bool */ public function is_connected(): bool { return isset($this->resource) && is_resource($this->resource) && !feof($this->resource); @@ -150,7 +180,13 @@ class websocket_client { /** * Sends text to the web socket server. * The web socket client wraps the payload in a web frame socket before sending on the socket. + * + * @param $resource * @param string|null $payload + * + * @return bool + * @throws \Random\RandomException + * @throws \socket_disconnected_exception */ public static function send($resource, ?string $payload): bool { if (!is_resource($resource)) { @@ -164,7 +200,7 @@ class websocket_client { } $frame_header = "\x81"; // FIN=1, opcode=1 (text frame) - $length = strlen($payload); + $length = strlen($payload); // Set mask bit and payload length if ($length <= 125) { @@ -176,7 +212,7 @@ class websocket_client { } // must be masked when sending to the server - $mask = random_bytes(4); + $mask = random_bytes(4); $masked_payload = ''; for ($i = 0; $i < $length; ++$i) { @@ -210,6 +246,17 @@ class websocket_client { } } + /** + * Returns a file path for a token. + * + * Tries to store in RAM first, otherwise uses the filesystem. + * + * @param string $token_name The name of the token. + * + * @return string The file path for the token. + * @see \sys_get_temp_dir() + * @link https://php.net/sys_get_temp_dir + */ public static function get_token_file($token_name): string { // Try to store in RAM first if (is_dir('/dev/shm') && is_writable('/dev/shm')) { @@ -221,8 +268,18 @@ class websocket_client { return $token_file; } + /** + * Sends a control frame over the WebSocket connection. + * + * This method sends a FIN=1 (final fragment) control frame with the given opcode and payload. + * + * @param int $opcode The opcode for the control frame. + * @param string $payload The payload to send, default is an empty string. + * + * @return void + */ private function send_control_frame(int $opcode, string $payload = ''): void { - $header = chr(0x80 | $opcode); // FIN=1, control frame + $header = chr(0x80 | $opcode); // FIN=1, control frame $payload_len = strlen($payload); // Payload length @@ -233,7 +290,7 @@ class websocket_client { } else { // Control frames should never be this large; truncate to 125 $payload = substr($payload, 0, 125); - $header .= chr(125); + $header .= chr(125); } @fwrite($this->resource, $header . $payload); @@ -241,7 +298,9 @@ class websocket_client { /** * Reads a web socket data frame and converts it to a regular string - * @param resource $this->resource + * + * @param resource $this ->resource + * * @return string */ public function read(): ?string { @@ -249,7 +308,7 @@ class websocket_client { throw new \RuntimeException("Not connected"); } - $final_frame = false; + $final_frame = false; $payload_data = ''; while (!$final_frame) { @@ -262,8 +321,8 @@ class websocket_client { $byte2 = ord($header[1]); $final_frame = ($byte1 >> 7) & 1; - $opcode = $byte1 & 0x0F; - $masked = ($byte2 >> 7) & 1; + $opcode = $byte1 & 0x0F; + $masked = ($byte2 >> 7) & 1; $payload_len = $byte2 & 0x7F; // Extended payload length @@ -335,8 +394,16 @@ class websocket_client { } // Helper function to fully read N bytes + + /** + * Reads up to the specified number of bytes from the underlying resource. + * + * @param int $length The maximum number of bytes to read. + * + * @return string|null The requested data, or null on error. + */ private function read_bytes(int $length): ?string { - $data = ''; + $data = ''; $max_chunk_size = stream_get_chunk_size($this->resource); // 20 tries waits 200 ms total per chunk @@ -376,16 +443,26 @@ class websocket_client { return $data; } + /** + * Sends an authentication request to the server. + * + * @param string $token_name The name of the token to authenticate with. + * @param string $token_hash The hash of the token to authenticate with. + * + * @return mixed|null The response from the server, or null on error. + */ public function authenticate($token_name, $token_hash) { return self::send($this->resource, json_encode(['service' => 'authentication', 'token' => ['name' => $token_name, 'hash' => $token_hash]])); } /** * Create a token for a service that can broadcast a message + * * @param string $service_name * @param string $service_class - * @param array $permissions - * @param int $time_limit_in_minutes + * @param array $permissions + * @param int $time_limit_in_minutes + * * @return array */ public static function create_service_token(string $service_name, string $service_class, array $permissions = [], int $time_limit_in_minutes = 0) { @@ -410,15 +487,15 @@ class websocket_client { // // Store the epoch time and time limit // - $array['token']['time'] = "" . time(); + $array['token']['time'] = "" . time(); $array['token']['limit'] = $time_limit_in_minutes; // // Store the service name used by web browser to subscribe // and store the class name of this service // - $array['service'] = true; - $array['service_name'] = $service_name; + $array['service'] = true; + $array['service_name'] = $service_name; $array['service_class'] = $service_class; // @@ -441,6 +518,14 @@ class websocket_client { // PHP <=7.4 compatibility - Replaced in PHP 8.0+ if (!function_exists('stream_get_chunk_size')) { + /** + * Returns the recommended chunk size for reading data from a stream. + * + * @param resource $stream The stream to retrieve the chunk size for. + * + * @return int The recommended chunk size. + * @link https://php.net/stream_get_chunk_size + */ function stream_get_chunk_size($stream): int { // For PHP versions lower then 8 we send the maximum size defined from https://php.net/stream_get_chunk_size return 8192; diff --git a/core/websockets/resources/classes/websocket_message.php b/core/websockets/resources/classes/websocket_message.php index 0aa81dd654..f3e8d0c6cb 100644 --- a/core/websockets/resources/classes/websocket_message.php +++ b/core/websockets/resources/classes/websocket_message.php @@ -29,17 +29,18 @@ /** * A structured web socket message easily converted to and from a json string * + * @param string $service_name ; + * @param string $token_name ; + * @param string $token_hash ; + * @param string $status_string ; + * @param string $status_code ; + * @param string $request_id ; + * @param string $resource_id ; + * @param string $domain_uuid ; + * @param string $permissions ; + * @param string $topic ; + * * @author Tim Fry - * @param string $service_name; - * @param string $token_name; - * @param string $token_hash; - * @param string $status_string; - * @param string $status_code; - * @param string $request_id; - * @param string $resource_id; - * @param string $domain_uuid; - * @param string $permissions; - * @param string $topic; */ class websocket_message extends base_message { @@ -58,30 +59,39 @@ class websocket_message extends base_message { public function __construct($associative_properties_array = []) { // Initialize empty default values - $this->service_name = ''; - $this->token_name = ''; - $this->token_hash = ''; + $this->service_name = ''; + $this->token_name = ''; + $this->token_hash = ''; $this->status_string = ''; - $this->status_code = ''; - $this->request_id = ''; - $this->resource_id = ''; - $this->domain_uuid = ''; - $this->domain_name = ''; - $this->permissions = []; - $this->topic = ''; + $this->status_code = ''; + $this->request_id = ''; + $this->resource_id = ''; + $this->domain_uuid = ''; + $this->domain_name = ''; + $this->permissions = []; + $this->topic = ''; // // Send to parent (base_message) constructor // parent::__construct($associative_properties_array); } + /** + * Checks if a permission is granted to this service. + * + * @param string $permission_name The name of the permission to check for. + * + * @return bool True if the permission is granted, false otherwise. + */ public function has_permission($permission_name) { return isset($this->permissions[$permission_name]); } /** * Alias of service_name. + * * @param string $service_name + * * @return $this * @see service_name */ @@ -97,7 +107,9 @@ class websocket_message extends base_message { * Gets or Sets the service name * If no parameters are provided then the service_name is returned. If the service name is provided, then the * service_name is set to the value provided. + * * @param string $service_name + * * @return $this */ public function service_name($service_name = null) { @@ -110,7 +122,9 @@ class websocket_message extends base_message { /** * Gets or sets the permissions array + * * @param array $permissions + * * @return $this */ public function permissions($permissions = []) { @@ -124,6 +138,7 @@ class websocket_message extends base_message { /** * Applies a filter to the payload of this message. * When a filter returns null then the payload is set to null + * * @param filter $filter */ public function apply_filter(?filter $filter) { @@ -134,9 +149,8 @@ class websocket_message extends base_message { if ($result === null) { $this->payload = null; return; - } - // Remove a key if filter does not pass - elseif(!$result) { + } // Remove a key if filter does not pass + elseif (!$result) { unset($this->payload[$key]); } } @@ -145,7 +159,9 @@ class websocket_message extends base_message { /** * Gets or sets the domain UUID + * * @param string $domain_uuid + * * @return $this or $domain_uuid */ public function domain_uuid($domain_uuid = '') { @@ -158,7 +174,9 @@ class websocket_message extends base_message { /** * Gets or sets the domain name + * * @param string $domain_name + * * @return $this or $domain_name */ public function domain_name($domain_name = '') { @@ -173,7 +191,9 @@ class websocket_message extends base_message { * Gets or Sets the service name * If no parameters are provided then the service_name is returned. If the service name is provided, then the * topic is set to the value provided. + * * @param string $topic + * * @return $this */ public function topic($topic = null) { @@ -186,7 +206,9 @@ class websocket_message extends base_message { /** * Gets or sets the token array using the key values of 'name' and 'hash' + * * @param array $token_array + * * @return array|$this * @see token_name * @see token_hash @@ -201,11 +223,13 @@ class websocket_message extends base_message { /** * Sets the token name + * * @param string $token_name + * * @return $this * @see token_hash */ - public function token_name($token_name = '') { + public function token_name($token_name = '') { if (func_num_args() > 0) { $this->token_name = $token_name; return $this; @@ -215,7 +239,9 @@ class websocket_message extends base_message { /** * Gets or sets the status code of this message + * * @param int $status_code + * * @return $this */ public function status_code($status_code = '') { @@ -228,7 +254,9 @@ class websocket_message extends base_message { /** * Gets or sets the resource id - * @param type $resource_id + * + * @param mixed $resource_id + * * @return $this */ public function resource_id($resource_id = null) { @@ -241,7 +269,9 @@ class websocket_message extends base_message { /** * Gets or sets the request ID - * @param type $request_id + * + * @param string $request_id + * * @return $this */ public function request_id($request_id = null) { @@ -254,10 +284,12 @@ class websocket_message extends base_message { /** * Gets or sets the status string - * @param type $status_string + * + * @param string $status_string + * * @return $this */ - public function status_string( $status_string = null) { + public function status_string($status_string = null) { if (func_num_args() > 0) { $this->status_string = $status_string; return $this; @@ -267,7 +299,9 @@ class websocket_message extends base_message { /** * Gets or sets the token hash - * @param type $token_hash + * + * @param string $token_hash + * * @return $this * @see token_name */ @@ -281,8 +315,10 @@ class websocket_message extends base_message { /** * Convert the 'statusString' key that comes from javascript - * @param type $status_string - * @return type + * + * @param string $status_string + * + * @return string */ public function statusString($status_string = '') { return $this->status_string($status_string); @@ -290,7 +326,9 @@ class websocket_message extends base_message { /** * Convert the 'statusCode' key that comes from javascript - * @param type $status_code + * + * @param string $status_code + * * @return $this */ public function statusCode($status_code = 200) { @@ -299,7 +337,9 @@ class websocket_message extends base_message { /** * Unwrap a JSON message to an associative array + * * @param string $json_string + * * @return array */ public static function unwrap($json_string = '') { @@ -308,7 +348,9 @@ class websocket_message extends base_message { /** * Helper function to respond with a connected message + * * @param string|int $request_id + * * @return string */ public static function connected($request_id = ''): string { @@ -317,7 +359,9 @@ class websocket_message extends base_message { /** * Helper function to respond with a authentication message + * * @param string|int $request_id + * * @return string */ public static function request_authentication($request_id = ''): string { @@ -334,9 +378,11 @@ class websocket_message extends base_message { /** * Helper function to respond with a bad request message + * * @param string|int $request_id - * @param string $service - * @param string $topic + * @param string $service + * @param string $topic + * * @return string */ public static function request_is_bad($request_id = '', string $service = '', string $topic = ''): string { @@ -352,28 +398,32 @@ class websocket_message extends base_message { /** * Helper function to respond with an authenticated message + * * @param string|int $request_id - * @param string $service - * @param string $topic + * @param string $service + * @param string $topic + * * @return string */ public static function request_authenticated($request_id = '', string $service = '', string $topic = 'authenticated'): string { $class = static::class; return (new $class()) - ->request_id($request_id) - ->service_name($service) - ->topic($topic) - ->status_code(200) - ->status_string('OK') - ->__toString() + ->request_id($request_id) + ->service_name($service) + ->topic($topic) + ->status_code(200) + ->status_string('OK') + ->__toString() ; } /** * Helper function to respond with an unauthorized request message + * * @param string|int $request_id - * @param string $service - * @param string $topic + * @param string $service + * @param string $topic + * * @return string */ public static function request_unauthorized($request_id = '', string $service = '', string $topic = 'unauthorized'): string { @@ -389,9 +439,11 @@ class websocket_message extends base_message { /** * Helper function to respond with a forbidden message + * * @param string|int $request_id - * @param string $service - * @param string $topic + * @param string $service + * @param string $topic + * * @return string */ public static function request_forbidden($request_id = '', string $service = '', string $topic = 'forbidden'): string { @@ -407,7 +459,9 @@ class websocket_message extends base_message { /** * Returns a websocket_message object (or child object) using the provided JSON string or JSON array + * * @param string|array $websocket_message_json JSON array or JSON string + * * @return static|null Returns a new websocket_message object (or child object) * @throws \InvalidArgumentException */ diff --git a/core/websockets/resources/classes/websocket_server.php b/core/websockets/resources/classes/websocket_server.php index 56ee28c6b5..8a79418c1a 100644 --- a/core/websockets/resources/classes/websocket_server.php +++ b/core/websockets/resources/classes/websocket_server.php @@ -40,94 +40,133 @@ class websocket_server { /** * Address to bind to. (Default 8080) + * * @var string */ protected $address; /** * Port to bind to. (Default 0.0.0.0 - all PHP detected IP addresses of the system) + * * @var int */ protected $port; /** * Tracks if the server is running + * * @var bool */ protected $running; /** * Resource or stream of the server socket binding + * * @var resource|stream */ protected $server_socket; /** * List of connected client sockets + * * @var array */ protected $clients; /** * Used to track on_message events + * * @var array */ private $message_callbacks; /** * Used to track on_connect events + * * @var array */ private $connect_callbacks; /** * Used to track on_disconnect events + * * @var array */ private $disconnect_callbacks; /** * Used to track switch listeners or other socket connection types + * * @var array */ private $listeners; /** * Creates a websocket_server instance + * * @param string $address IP to bind (default 0.0.0.0) * @param int $port TCP port (default 8080) */ public function __construct(string $address = '127.0.0.1', int $port = 8080) { $this->running = false; $this->address = $address; - $this->port = $port; + $this->port = $port; // Initialize arrays - $this->listeners = []; - $this->clients = []; - $this->message_callbacks = []; - $this->connect_callbacks = []; + $this->listeners = []; + $this->clients = []; + $this->message_callbacks = []; + $this->connect_callbacks = []; $this->disconnect_callbacks = []; } + /** + * Log a debugging message to the log handler. + * + * @param string $message The message to be logged. + * + * @return void + */ private function debug(string $message) { self::log($message, LOG_DEBUG); } + /** + * Log a warning message to the log file. + * + * @param string $message The warning message to be logged. + * + * @return void + */ private function warn(string $message) { self::log($message, LOG_WARNING); } + /** + * Log an error message to the log file. If the logging fails for any reason, it is silently ignored and no further action is taken. + * + * @param string $message The error message to be logged. + * + * @return void + */ private function error(string $message) { self::log($message, LOG_ERR); } + /** + * Logs information level message to the log handler. + * + * @param string $message The message to be logged. + * + * @return void + */ private function info(string $message) { self::log($message, LOG_INFO); } /** * Starts server: accepts new clients, reads frames, and broadcasts messages. + * * @returns int A non-zero indicates an abnormal termination */ public function run(): int { @@ -143,8 +182,8 @@ class websocket_server { while ($this->running) { $listeners = array_column($this->listeners, 0); - $read = array_merge([$this->server_socket], $listeners, $this->clients); - $write = $except = []; + $read = array_merge([$this->server_socket], $listeners, $this->clients); + $write = $except = []; // Server connection issue if (false === stream_select($read, $write, $except, null)) { $this->running = false; @@ -194,12 +233,15 @@ class websocket_server { $this->trigger_message($client_socket, $message); } } + return 0; } /** * Add a non-blocking socket to listen for traffic on + * * @param resource $socket * @param callable $on_data_ready_callback Callable function to call when data arrives on the socket + * * @throws \InvalidArgumentException */ public function add_listener($socket, callable $on_data_ready_callback) { @@ -211,6 +253,7 @@ class websocket_server { /** * Returns true if there are connected web socket clients. + * * @return bool */ public function has_clients(): bool { @@ -220,7 +263,9 @@ class websocket_server { /** * When a web socket message is received the $on_message_callback function is called. * Multiple on_message functions can be specified. + * * @param callable $on_message_callback Callable function to call when data arrives on the socket + * * @throws InvalidArgumentException */ public function on_message(callable $on_message_callback) { @@ -232,8 +277,10 @@ class websocket_server { /** * Calls all the on_message functions + * * @param resource $socket - * @param string $message + * @param string $message + * * @return void */ private function trigger_message($socket, string $message) { @@ -249,7 +296,9 @@ class websocket_server { /** * When a web socket handshake has completed, the $on_connect_callback function is called. * Multiple on_connect functions can be specified. + * * @param callable $on_connect_callback Callable function to call when a new connection occurs. + * * @throws InvalidArgumentException */ public function on_connect(callable $on_connect_callback) { @@ -261,7 +310,10 @@ class websocket_server { /** * Calls all the on_connect functions + * * @param resource $socket + * + * @throws \socket_disconnected_exception */ private function trigger_connect($socket) { foreach ($this->connect_callbacks as $callback) { @@ -275,7 +327,11 @@ class websocket_server { /** * When a web socket has disconnected, the $on_disconnect_callback function is called. * Multiple functions can be specified with subsequent calls - * @param string|callable $on_disconnect_callback Callable function to call when a socket disconnects. The function must accept a single parameter for the socket that was disconnected. + * + * @param string|callable $on_disconnect_callback Callable function to call when a socket disconnects. The function + * must accept a single parameter for the socket that was + * disconnected. + * * @throws InvalidArgumentException */ public function on_disconnect($on_disconnect_callback) { @@ -287,7 +343,8 @@ class websocket_server { /** * Calls all the on_disconnect_callback functions - * @param type $socket + * + * @param resource $socket */ private function trigger_disconnect($socket) { foreach ($this->disconnect_callbacks as $callback) { @@ -297,6 +354,7 @@ class websocket_server { /** * Returns the socket used in the server connection + * * @return resource */ public function get_socket() { @@ -304,15 +362,19 @@ class websocket_server { } /** - * Remove a client socket on disconnect. - * @return bool Returns true on client disconnect and false when the client is not found in the tracking array + * Disconnect a client from the server. + * + * @param resource $resource The socket or resource id of the client to disconnect. + * @param string|null $error A custom error message to send to the client, if any. + * + * @return bool True if the client was successfully disconnected, false otherwise. */ - protected function disconnect_client($socket, $error = null): bool { + protected function disconnect_client($resource, $error = null): bool { $index = array_search($resource, $this->clients, true); if ($index !== false) { self::disconnect($resource); unset($this->clients[$index]); - $this->trigger_disconnect($socket); + $this->trigger_disconnect($resource); return true; } return false; @@ -320,7 +382,8 @@ class websocket_server { /** * Sends a disconnect frame with no payload - * @param type $resource + * + * @param resource $resource */ public static function disconnect($resource) { if (is_resource($resource)) { @@ -332,7 +395,8 @@ class websocket_server { /** * Performs web socket handshake on new connection. - * @param type $socket Socket to perform the handshake on. + * + * @param resource $socket Socket to perform the handshake on. */ protected function handshake($socket) { // ensure blocking to read full header @@ -347,21 +411,23 @@ class websocket_server { if (!preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $request_header, $matches)) { throw new \invalid_handshake_exception($socket, "Invalid WebSocket handshake"); } - $key = trim($matches[1]); - $accept_key = base64_encode( - sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true) + $key = trim($matches[1]); + $accept_key = base64_encode( + sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true) ); $response_header = "HTTP/1.1 101 Switching Protocols\r\n" - . "Upgrade: websocket\r\n" - . "Connection: Upgrade\r\n" - . "Sec-WebSocket-Accept: {$accept_key}\r\n\r\n"; + . "Upgrade: websocket\r\n" + . "Connection: Upgrade\r\n" + . "Sec-WebSocket-Accept: {$accept_key}\r\n\r\n"; fwrite($socket, $response_header); } /** * Read specific number of bytes from a web socket + * * @param resource $socket - * @param int $length + * @param int $length + * * @return string */ private function read_bytes($socket, int $length): string { @@ -379,15 +445,17 @@ class websocket_server { /** * Reads a web socket data frame and converts it to a regular string + * * @param resource $socket - * @return string + * + * @return string|null */ - private function receive_frame($socket): string { + private function receive_frame($socket): ?string { if (!is_resource($socket)) { throw new \RuntimeException("Not connected"); } - $final_frame = false; + $final_frame = false; $payload_data = ''; while (!$final_frame) { @@ -399,8 +467,8 @@ class websocket_server { $byte2 = ord($header[1]); $final_frame = ($byte1 >> 7) & 1; - $opcode = $byte1 & 0x0F; - $masked = ($byte2 >> 7) & 1; + $opcode = $byte1 & 0x0F; + $masked = ($byte2 >> 7) & 1; $payload_len = $byte2 & 0x7F; // Extended payload length @@ -480,8 +548,11 @@ class websocket_server { /** * Send text frame to client. If the socket connection is not a valid resource, the send * method will fail silently and return false. - * @param resource $resource The socket or resource id to communicate on. - * @param string|null $payload The message to send to the clients. Sending null as the message sends a close frame packet. + * + * @param resource $resource The socket or resource id to communicate on. + * @param string|null $payload The message to send to the clients. Sending null as the message sends a close frame + * packet. + * * @return bool True if message was sent on the provided resource or false if there was an error. */ public static function send($resource, ?string $payload): bool { @@ -496,20 +567,20 @@ class websocket_server { return true; } - $chunk_size = 4096; // 4 KB + $chunk_size = 4096; // 4 KB $payload_len = strlen($payload); - $offset = 0; - $first = true; + $offset = 0; + $first = true; while ($offset < $payload_len) { $remaining = $payload_len - $offset; - $chunk = substr($payload, $offset, min($chunk_size, $remaining)); + $chunk = substr($payload, $offset, min($chunk_size, $remaining)); $chunk_len = strlen($chunk); // Determine FIN bit and opcode - $fin = ($offset + $chunk_size >= $payload_len) ? 0x80 : 0x00; // 0x80 if final + $fin = ($offset + $chunk_size >= $payload_len) ? 0x80 : 0x00; // 0x80 if final $opcode = $first ? 0x1 : 0x0; // text for first frame, continuation for rest - $first = false; + $first = false; // Build header $header = chr($fin | $opcode); @@ -542,7 +613,9 @@ class websocket_server { /** * Get the IP and port of the connected remote system. + * * @param socket $socket The socket stream of the connection + * * @return array An associative array of remote_ip and remote_port */ public static function get_remote_info($socket): array { @@ -552,9 +625,10 @@ class websocket_server { /** * Print socket information + * * @param resource $resource - * @param bool $return If you would like to capture the output of print_r(), use the return parameter. When this - * parameter is set to true, print_r() will return the information rather than print it. + * @param bool $return If you would like to capture the output of print_r(), use the return parameter. When this + * parameter is set to true, print_r() will return the information rather than print it. */ public static function print_stream_info($resource, $return = false) { if (is_resource($resource)) { diff --git a/core/websockets/resources/classes/websocket_service.php b/core/websockets/resources/classes/websocket_service.php index 32a4235b92..c9891e527c 100644 --- a/core/websockets/resources/classes/websocket_service.php +++ b/core/websockets/resources/classes/websocket_service.php @@ -35,48 +35,56 @@ class websocket_service extends service { /** * Address to bind to. (Default 8080) + * * @var string */ protected $ip; /** * Port to bind to. (Default 0.0.0.0 - all PHP detected IP addresses of the system) + * * @var int */ protected $port; /** * Resource or stream of the server socket binding + * * @var resource|stream */ protected $server_socket; /** * List of connected client sockets + * * @var array */ protected $clients; /** * Used to track on_message events + * * @var array */ protected $message_callbacks; /** * Used to track on_connect events + * * @var array */ protected $connect_callbacks; /** * Used to track on_disconnect events + * * @var array */ protected $disconnect_callbacks; /** * Used to track switch listeners or other socket connection types + * * @var array */ protected $listeners; @@ -84,12 +92,14 @@ class websocket_service extends service { /** * Subscriber Objects + * * @var subscriber */ protected $subscribers; /** * Array of registered services + * * @var array */ private $services; @@ -100,18 +110,19 @@ class websocket_service extends service { /** * Reload settings + * * @return void * @throws \RuntimeException * @access protected */ protected function reload_settings(): void { // Initialize tracking arrays - $this->listeners = []; - $this->clients = []; - $this->message_callbacks = []; - $this->connect_callbacks = []; + $this->listeners = []; + $this->clients = []; + $this->message_callbacks = []; + $this->connect_callbacks = []; $this->disconnect_callbacks = []; - $this->subscribers = []; + $this->subscribers = []; $settings = new settings(['database' => database::new(['config' => config::load()])]); @@ -134,6 +145,7 @@ class websocket_service extends service { /** * Display the version on the console + * * @return void * @access protected */ @@ -143,6 +155,7 @@ class websocket_service extends service { /** * Set extra command options from the command line + * * @access protected */ protected static function set_command_options() { @@ -170,6 +183,13 @@ class websocket_service extends service { } } + /** + * Retrieves a subscriber object from the given socket ID. + * + * @param mixed $socket The socket ID to search for + * + * @return subscriber|null The matching subscriber, or null if not found + */ private function get_subscriber_from_socket_id($socket): ?subscriber { $subscriber = null; // Get the subscriber based on their socket ID @@ -182,6 +202,16 @@ class websocket_service extends service { return $subscriber; } + /** + * Authenticate a subscriber based on the provided token and message. + * + * @param subscriber $subscriber The subscriber to authenticate. + * @param websocket_message $message The message containing the authentication token. + * + * @return bool Whether the authentication was successful or not. + * @throws \socket_disconnected_exception + * @throws \subscriber_token_expired_exception + */ private function authenticate_subscriber(subscriber $subscriber, websocket_message $message) { $this->info("Authenticating client: $subscriber->id"); @@ -204,7 +234,7 @@ class websocket_service extends service { foreach ($subscriptions as $subscribed_to) { if (isset($this->services[$subscribed_to])) { $subscriber_service = $this->services[$subscribed_to]; - $class_name = $subscriber_service->service_class(); + $class_name = $subscriber_service->service_class(); // Make sure we can call the 'create_filter_chain_for' method if (is_a($class_name, 'websocket_service_interface', true)) { // Call the service class method to validate the subscriber @@ -227,6 +257,14 @@ class websocket_service extends service { return; } + /** + * Broadcast a message to all subscribers except the specified broadcaster. + * + * @param subscriber $broadcaster The subscriber that is broadcasting the message. + * @param websocket_message|null $message The message being broadcasted. If null, do nothing. + * + * @return void + */ private function broadcast_service_message(subscriber $broadcaster, ?websocket_message $message = null) { $this->debug("Processing Broadcast"); @@ -268,8 +306,7 @@ class websocket_service extends service { $this->handle_disconnect($subscriber->socket_id()); } } - } - // Route a specific request from a service back to a subscriber + } // Route a specific request from a service back to a subscriber else { // Get the subscriber object hash $object_id = $message->resource_id; @@ -288,9 +325,11 @@ class websocket_service extends service { /** * Filters subscribers based on the service name given - * @param array $subscribers + * + * @param array $subscribers * @param websocket_message $message - * @param string $service_name + * @param string $service_name + * * @return array List of subscriber objects or an empty array if there are no subscribers to that service name */ private function filter_subscribers(array $subscribers, websocket_message $message, string $service_name): array { @@ -299,7 +338,7 @@ class websocket_service extends service { foreach ($subscribers as $subscriber) { $caller_context = strtolower($message->caller_context ?? ''); if (!empty($caller_context) && $subscriber->has_subscribed_to($service_name) && ($subscriber->show_all || $caller_context === $subscriber->domain_name || $caller_context === 'public' || $caller_context === 'default' - ) + ) ) { $filtered[] = $subscriber; } else { @@ -313,13 +352,15 @@ class websocket_service extends service { /** * Create a subscriber for each connection + * * @param resource $socket + * * @return void */ private function handle_connect($socket) { // We catch only the socket disconnection exception as there is a general try/catch already try { - $subscriber = new subscriber($socket, [websocket_service::class, 'send']); + $subscriber = new subscriber($socket, [websocket_service::class, 'send']); $this->subscribers[$subscriber->id] = $subscriber; $subscriber->send(websocket_message::connected()); } catch (\socket_disconnected_exception $sde) { @@ -332,6 +373,7 @@ class websocket_service extends service { /** * Web socket client disconnected from the server or this service has requested a disconnect from the subscriber + * * @param subscriber|resource|int|string $object_or_resource_or_id */ private function handle_disconnect($object_or_resource_or_id) { @@ -377,8 +419,9 @@ class websocket_service extends service { /** * When a message event occurs, send to all the subscribers + * * @param resource $socket - * @param mixed $data + * @param mixed $data */ private function handle_message($socket, $data) { $subscriber = $this->get_subscriber_from_socket_id($socket); @@ -436,6 +479,14 @@ class websocket_service extends service { } } + /** + * Handle a client message by routing it to its intended service. + * + * @param subscriber $subscriber The client subscriber instance associated with the incoming message. + * @param websocket_message $message The incoming WebSocket message containing details about the request. + * + * @return void + */ private function handle_client_message(subscriber $subscriber, websocket_message $message) { //find the service with that name foreach ($this->subscribers as $service) { @@ -454,7 +505,7 @@ class websocket_service extends service { $message->resource_id = $subscriber->id; //send the modified web socket message to the service - $service->send((string) $message); + $service->send((string)$message); //continue searching for service providers continue; @@ -465,6 +516,7 @@ class websocket_service extends service { /** * Runs the web socket server binding to the ip and port set in default settings * The run method will stop if the SIG_TERM or SIG_HUP signal is processed in the parent + * * @return int * @throws \RuntimeException * @throws socket_exception @@ -494,7 +546,7 @@ class websocket_service extends service { // // Merge all sockets to a single array // - $read = array_merge([$this->server_socket], $this->clients); + $read = array_merge([$this->server_socket], $this->clients); $write = $except = []; //$this->debug("Waiting on event. Connected Clients: (".count($this->clients).")", LOG_DEBUG); @@ -577,10 +629,10 @@ class websocket_service extends service { // Get the error details // $subscriber_id = $se->getSubscriberId(); - $message = $se->getMessage(); - $code = $se->getCode(); - $file = $se->getFile(); - $line = $se->getLine(); + $message = $se->getMessage(); + $code = $se->getCode(); + $file = $se->getFile(); + $line = $se->getLine(); // // Dump the details in the log @@ -595,10 +647,12 @@ class websocket_service extends service { } } } + return 0; } /** * Overrides the parent class to shutdown all sockets + * * @override service */ public function __destruct() { @@ -610,12 +664,18 @@ class websocket_service extends service { parent::__destruct(); } + /** + * Retrieves an array of open sockets. + * + * @return array An array containing open socket connections. + */ public function get_open_sockets(): array { return $this->clients; } /** * Returns true if there are connected web socket clients. + * * @return bool */ public function has_clients(): bool { @@ -625,7 +685,9 @@ class websocket_service extends service { /** * When a web socket message is received the $on_message_callback function is called. * Multiple on_message functions can be specified. + * * @param callable $on_message_callback + * * @throws InvalidArgumentException */ public function on_message(callable $on_message_callback) { @@ -637,8 +699,10 @@ class websocket_service extends service { /** * Calls all the on_message functions + * * @param resource $resource - * @param string $message + * @param string $message + * * @return void * @access protected */ @@ -652,7 +716,9 @@ class websocket_service extends service { /** * When a web socket handshake has completed, the $on_connect_callback function is called. * Multiple on_connect functions can be specified. + * * @param callable $on_connect_callback + * * @throws InvalidArgumentException */ public function on_connect(callable $on_connect_callback) { @@ -664,7 +730,9 @@ class websocket_service extends service { /** * Calls all the on_connect functions + * * @param resource $resource + * * @access protected */ protected function trigger_connect($resource) { @@ -676,7 +744,9 @@ class websocket_service extends service { /** * When a web socket has disconnected, the $on_disconnect_callback function is called. * Multiple functions can be specified with subsequent calls + * * @param string|callable $on_disconnect_callback + * * @throws InvalidArgumentException */ public function on_disconnect($on_disconnect_callback) { @@ -688,7 +758,9 @@ class websocket_service extends service { /** * Calls all the on_disconnect_callback functions + * * @param resource $socket + * * @access protected */ protected function trigger_disconnect($socket) { @@ -699,6 +771,7 @@ class websocket_service extends service { /** * Returns the socket used in the server connection + * * @return resource */ public function get_socket() { @@ -707,7 +780,9 @@ class websocket_service extends service { /** * Remove a client socket on disconnect. + * * @param resource $resource Resource for the socket connection + * * @return bool Returns true on client disconnect and false when the client is not found in the tracking array * @access protected */ @@ -750,6 +825,8 @@ class websocket_service extends service { /** * Performs web socket handshake on new connection. + * + * @param resource $resource * @access protected */ protected function handshake($resource): void { @@ -765,21 +842,23 @@ class websocket_service extends service { if (!preg_match("/Sec-WebSocket-Key: (.*)\r\n/i", $request_header, $matches)) { throw new invalid_handshake_exception($resource, "Invalid WebSocket handshake"); } - $key = trim($matches[1]); - $accept_key = base64_encode( - sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true) + $key = trim($matches[1]); + $accept_key = base64_encode( + sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true) ); $response_header = "HTTP/1.1 101 Switching Protocols\r\n" - . "Upgrade: websocket\r\n" - . "Connection: Upgrade\r\n" - . "Sec-WebSocket-Accept: {$accept_key}\r\n\r\n"; + . "Upgrade: websocket\r\n" + . "Connection: Upgrade\r\n" + . "Sec-WebSocket-Accept: {$accept_key}\r\n\r\n"; fwrite($resource, $response_header); } /** * Read specific number of bytes from a websocket + * * @param resource $socket - * @param int $length + * @param int $length + * * @return string */ private function read_bytes($socket, int $length): string { @@ -797,7 +876,9 @@ class websocket_service extends service { /** * Reads a websocket data frame and converts it to a regular string + * * @param resource $socket + * * @return string */ private function receive_frame($socket): string { @@ -810,8 +891,8 @@ class websocket_service extends service { $this->update_connected_clients(); return ''; } - $bytes = unpack('Cfirst/Csecond', $hdr); - $fin = ($bytes['first'] >> 7) & 0x1; + $bytes = unpack('Cfirst/Csecond', $hdr); + $fin = ($bytes['first'] >> 7) & 0x1; $opcode = $bytes['first'] & 0x0F; $masked = ($bytes['second'] >> 7) & 0x1; $length = $bytes['second'] & 0x7F; @@ -829,7 +910,7 @@ class websocket_service extends service { if (strlen($ext) < 8) return ''; // unpack 64-bit BE; PHP 7.0+: use J, else fallback - $arr = unpack('J', $ext); + $arr = unpack('J', $ext); $length = $arr[1]; } @@ -863,8 +944,10 @@ class websocket_service extends service { /** * Send text frame to client. If the socket connection is not a valid resource, the send * method will fail silently and return false. - * @param resource $resource The socket or resource id to communicate on. - * @param string|null $payload The string to wrap in a web socket frame to send to the clients + * + * @param resource $resource The socket or resource id to communicate on. + * @param string|null $payload The string to wrap in a web socket frame to send to the clients + * * @return bool */ public static function send($resource, ?string $payload): bool { @@ -878,7 +961,7 @@ class websocket_service extends service { } $payload_length = strlen($payload); - $frame_header = "\x81"; // FIN = 1, text frame + $frame_header = "\x81"; // FIN = 1, text frame // Create frame header if ($payload_length <= 125) { $frame_header .= chr($payload_length); @@ -893,7 +976,7 @@ class websocket_service extends service { // Attempt to write full frame $written = @fwrite($resource, $frame); if ($written === false) { - self::log("fwrite() failed for socket " . (int) $resource, LOG_ERR); + self::log("fwrite() failed for socket " . (int)$resource, LOG_ERR); throw new socket_disconnected_exception($resource); } @@ -907,7 +990,9 @@ class websocket_service extends service { /** * Get the IP and port of the connected remote system. + * * @param resource $resource The resource or stream of the connection + * * @return array An associative array of remote_ip and remote_port */ public static function get_remote_info($resource): array {