From 34821bed7e3a06ea66f0d4eaf8e54e2adf22411f Mon Sep 17 00:00:00 2001
From: frytimo
Date: Wed, 19 Nov 2025 12:48:36 -0400
Subject: [PATCH] Documentation, format class, no modification. (#7629)
---
resources/classes/array_order.php | 41 +-
resources/classes/auto_loader.php | 378 +-
resources/classes/base2n.php | 84 +-
resources/classes/button.php | 235 +-
resources/classes/cache.php | 348 +-
resources/classes/captcha.php | 51 +-
resources/classes/command_option.php | 138 +-
resources/classes/config.php | 350 +-
resources/classes/database.php | 5322 +++++++++---------
resources/classes/domains.php | 1343 ++---
resources/classes/email.php | 1090 ++--
resources/classes/event_socket.php | 265 +-
resources/classes/file.php | 135 +-
resources/classes/filter_chain.php | 11 +-
resources/classes/google_authenticator.php | 73 +-
resources/classes/groups.php | 1041 ++--
resources/classes/invalid_uuid_exception.php | 13 +-
resources/classes/logging.php | 410 +-
resources/classes/menu.php | 2948 +++++-----
resources/classes/message.php | 98 +-
resources/classes/modal.php | 100 +-
resources/classes/parsedown.php | 4221 +++++++-------
resources/classes/permissions.php | 218 +-
resources/classes/schema.php | 1590 +++---
resources/classes/service.php | 1220 ++--
resources/classes/settings.php | 298 +-
resources/classes/sounds.php | 122 +-
resources/classes/switch_settings.php | 573 +-
resources/classes/template.php | 144 +-
resources/classes/text.php | 786 +--
resources/classes/token.php | 104 +-
resources/classes/tones.php | 100 +-
resources/classes/user.php | 83 +-
resources/classes/vcard.php | 290 +-
resources/classes/waveform.php | 282 +-
resources/classes/xml.php | 28 +-
36 files changed, 12982 insertions(+), 11551 deletions(-)
diff --git a/resources/classes/array_order.php b/resources/classes/array_order.php
index 142193e22a..7fcfc48461 100644
--- a/resources/classes/array_order.php
+++ b/resources/classes/array_order.php
@@ -6,23 +6,42 @@ class array_order {
var $backwards = false;
var $numeric = false;
+ /**
+ * Sorts the provided array based on the specified fields.
+ *
+ * If no fields are provided, sorts in default order. If numeric sorting is enabled,
+ * uses the numericCompare method for comparison; otherwise, uses the stringCompare method.
+ *
+ * @param array $array The array to be sorted
+ *
+ * @return array The sorted array
+ */
function sort() {
$args = func_get_args();
$array = $args[0];
- if (!$array) return array();
+ if (!$array) return [];
$this->sort_fields = array_slice($args, 1);
if (!$this->sort_fields) return $array();
if ($this->numeric) {
- usort($array, array($this, 'numericCompare'));
+ usort($array, [$this, 'numericCompare']);
} else {
- usort($array, array($this, 'stringCompare'));
+ usort($array, [$this, 'stringCompare']);
}
return $array;
}
+ /**
+ * Compares two values based on a specified set of sort fields.
+ *
+ * @param array $a The first value to compare.
+ * @param array $b The second value to compare.
+ *
+ * @return int A negative integer if the first value is less than the second, a positive integer if the first value
+ * is greater than the second, and zero if they are equal.
+ */
function numericCompare($a, $b) {
- foreach($this->sort_fields as $sort_field) {
+ foreach ($this->sort_fields as $sort_field) {
if ($a[$sort_field] == $b[$sort_field]) {
continue;
}
@@ -31,8 +50,17 @@ class array_order {
return 0;
}
+ /**
+ * Compares two strings according to the specified sort fields.
+ *
+ * @param string $a The first string to compare.
+ * @param string $b The second string to compare.
+ *
+ * @return int A negative integer if $a is less than $b, a positive integer if $a is greater than $b,
+ * and 0 if the strings are equal according to the specified sort fields.
+ */
function stringCompare($a, $b) {
- foreach($this->sort_fields as $sort_field) {
+ foreach ($this->sort_fields as $sort_field) {
$cmp_result = strcasecmp($a[$sort_field], $b[$sort_field]);
if ($cmp_result == 0) continue;
return ($this->backwards ? -$cmp_result : $cmp_result);
@@ -40,7 +68,6 @@ class array_order {
return 0;
}
}
+
//$order = new array_order();
//$registrations = $order->sort($registrations, 'domain', 'user');
-
-?>
\ No newline at end of file
diff --git a/resources/classes/auto_loader.php b/resources/classes/auto_loader.php
index 03526acf50..98c1b9a31b 100644
--- a/resources/classes/auto_loader.php
+++ b/resources/classes/auto_loader.php
@@ -38,38 +38,41 @@ class auto_loader {
const CLASSES_FILE = 'autoloader_cache.php';
const INTERFACES_KEY = "autoloader_interfaces";
const INTERFACES_FILE = "autoloader_interface_cache.php";
-
- private $classes;
-
- /**
- * Tracks the APCu extension for caching to RAM drive across requests
- * @var bool
- */
- private $apcu_enabled;
-
/**
* Cache path and file name for classes
+ *
* @var string
*/
private static $classes_file = null;
-
+ /**
+ * Cache path and file name for interfaces
+ *
+ * @var string
+ */
+ private static $interfaces_file = null;
+ private $classes;
+ /**
+ * Tracks the APCu extension for caching to RAM drive across requests
+ *
+ * @var bool
+ */
+ private $apcu_enabled;
/**
* Maps interfaces to classes
+ *
* @var array
*/
private $interfaces;
-
/**
* @var array
*/
private $traits;
/**
- * Cache path and file name for interfaces
- * @var string
+ * Initializes the class and sets up caching mechanisms.
+ *
+ * @param bool $disable_cache If true, disables cache usage. Defaults to false.
*/
- private static $interfaces_file = null;
-
public function __construct($disable_cache = false) {
//set if we can use RAM cache
@@ -93,130 +96,14 @@ class auto_loader {
$this->update_cache();
}
//register this object to load any unknown classes
- spl_autoload_register(array($this, 'loader'));
+ spl_autoload_register([$this, 'loader']);
}
/**
- * The loader is set to private because only the PHP engine should be calling this method
- * @param string $class_name The class name that needs to be loaded
- * @return bool True if the class is loaded or false when the class is not found
- * @access private
+ * Loads the class cache from various sources.
+ *
+ * @return bool True if the cache is loaded successfully, false otherwise.
*/
- private function loader($class_name): bool {
-
- //sanitize the class name
- $class_name = preg_replace('[^a-zA-Z0-9_]', '', $class_name);
-
- //find the path using the class_name as the key in the classes array
- if (isset($this->classes[$class_name])) {
- //include the class or interface
- include_once $this->classes[$class_name];
-
- //return boolean
- return true;
- }
-
- //Smarty has it's own autoloader so reject the request
- if ($class_name === 'Smarty_Autoloader') {
- return false;
- }
-
- //cache miss
- self::log(LOG_WARNING, "class '$class_name' not found in cache");
-
- //set project path using magic dir constant
- $project_path = dirname(__DIR__, 2);
-
- //build the search path array
- $search_path[] = glob($project_path . "/resources/interfaces/" . $class_name . ".php");
- $search_path[] = glob($project_path . "/resources/traits/" . $class_name . ".php");
- $search_path[] = glob($project_path . "/resources/classes/" . $class_name . ".php");
- $search_path[] = glob($project_path . "/*/*/resources/interfaces/" . $class_name . ".php");
- $search_path[] = glob($project_path . "/*/*/resources/traits/" . $class_name . ".php");
- $search_path[] = glob($project_path . "/*/*/resources/classes/" . $class_name . ".php");
-
- //fix class names in the plugins directory prefixed with 'plugin_'
- if (str_starts_with($class_name, 'plugin_')) {
- $class_name = substr($class_name, 7);
- }
- $search_path[] = glob($project_path . "/core/authentication/resources/classes/plugins/" . $class_name . ".php");
-
- //collapse all entries to only the matched entry
- $matches = array_filter($search_path);
- if (!empty($matches)) {
- $path = array_pop($matches)[0];
-
- //include the class, interface, or trait
- include_once $path;
-
- //inject the class in to the array
- $this->classes[$class_name] = $path;
-
- //update the cache with new classes
- $this->update_cache();
-
- //return boolean
- return true;
- }
-
- //send to syslog when debugging
- self::log(LOG_ERR, "class '$class_name' not found name");
-
- //return boolean
- return false;
- }
-
- /**
- * Update the auto loader
- */
- public function update() {
- self::clear_cache();
- $this->reload_classes();
- $this->update_cache();
- }
-
- public function update_cache(): bool {
- //guard against writing an empty file
- if (empty($this->classes)) {
- return false;
- }
-
- //update RAM cache when available
- if ($this->apcu_enabled) {
- $classes_cached = apcu_store(self::CLASSES_KEY, $this->classes);
- $interfaces_cached = apcu_store(self::INTERFACES_KEY, $this->interfaces);
- //do not save to drive when we are using apcu
- if ($classes_cached && $interfaces_cached)
- return true;
- }
-
- //export the classes array using PHP engine
- $classes_array = var_export($this->classes, true);
-
- //put the array in a form that it can be loaded directly to an array
- $class_result = file_put_contents(self::$classes_file, "interfaces, true);
-
- //put the array in a form that it can be loaded directly to an array
- $interface_result = file_put_contents(self::$interfaces_file, "classes = [];
$this->interfaces = [];
@@ -251,6 +138,15 @@ class auto_loader {
return (!empty($this->classes) && !empty($this->interfaces));
}
+ /**
+ * Reloads classes and interfaces from the project's resources.
+ *
+ * This method scans all PHP files in the specified locations, parses their contents,
+ * and updates the internal storage of classes and interfaces. It also processes
+ * implementation relationships between classes and interfaces.
+ *
+ * @return void
+ */
public function reload_classes() {
//set project path using magic dir constant
$project_path = dirname(__DIR__, 2);
@@ -350,42 +246,85 @@ class auto_loader {
}
/**
- * Returns a list of classes loaded by the auto_loader. If no classes have been loaded an empty array is returned.
- * @return array List of classes loaded by the auto_loader or empty array
+ * Updates the cache by writing the classes and interfaces to files on disk.
+ *
+ * @return bool True if the update was successful, false otherwise
*/
- public function get_class_list(): array {
- if (!empty($this->classes)) {
- return $this->classes;
+ public function update_cache(): bool {
+ //guard against writing an empty file
+ if (empty($this->classes)) {
+ return false;
}
- return [];
+
+ //update RAM cache when available
+ if ($this->apcu_enabled) {
+ $classes_cached = apcu_store(self::CLASSES_KEY, $this->classes);
+ $interfaces_cached = apcu_store(self::INTERFACES_KEY, $this->interfaces);
+ //do not save to drive when we are using apcu
+ if ($classes_cached && $interfaces_cached)
+ return true;
+ }
+
+ //export the classes array using PHP engine
+ $classes_array = var_export($this->classes, true);
+
+ //put the array in a form that it can be loaded directly to an array
+ $class_result = file_put_contents(self::$classes_file, "interfaces, true);
+
+ //put the array in a form that it can be loaded directly to an array
+ $interface_result = file_put_contents(self::$interfaces_file, "classes) || empty($this->interfaces)) {
- return [];
+ private static function log(int $level, string $message): void {
+ if (filter_var($_REQUEST['debug'] ?? false, FILTER_VALIDATE_BOOLEAN) || filter_var(getenv('DEBUG') ?? false, FILTER_VALIDATE_BOOLEAN)) {
+ openlog("PHP", LOG_PID | LOG_PERROR, LOG_LOCAL0);
+ syslog($level, "[auto_loader] " . $message);
+ closelog();
}
- //check if we have an interface with that name
- if (!empty($this->interfaces[$interface_name])) {
- //return the list of classes associated with that interface
- return $this->interfaces[$interface_name];
- }
- //interface is not implemented by any classes
- return [];
}
- public function get_interfaces(): array {
- if (!empty($this->interfaces)) {
- return $this->interfaces;
- }
- return [];
+ /**
+ * Main method used to update internal state by clearing cache, reloading classes and updating cache.
+ *
+ * @return void
+ * @see \auto_loader::clear_cache()
+ * @see \auto_loader::reload_classes()
+ * @see \auto_loader::update_cache()
+ */
+ public function update() {
+ self::clear_cache();
+ $this->reload_classes();
+ $this->update_cache();
}
+ /**
+ * Clears the cache of stored classes and interfaces.
+ *
+ * @return void
+ */
public static function clear_cache() {
//check for apcu cache
@@ -426,11 +365,120 @@ class auto_loader {
}
}
- private static function log(int $level, string $message): void {
- if (filter_var($_REQUEST['debug'] ?? false, FILTER_VALIDATE_BOOL) || filter_var(getenv('DEBUG') ?? false, FILTER_VALIDATE_BOOL)) {
- openlog("PHP", LOG_PID | LOG_PERROR, LOG_LOCAL0);
- syslog($level, "[auto_loader] " . $message);
- closelog();
+ /**
+ * Returns a list of classes loaded by the auto_loader. If no classes have been loaded an empty array is returned.
+ *
+ * @return array List of classes loaded by the auto_loader or empty array
+ */
+ public function get_class_list(): array {
+ if (!empty($this->classes)) {
+ return $this->classes;
}
+ return [];
+ }
+
+ /**
+ * Returns a list of classes implementing the interface
+ *
+ * @param string $interface_name
+ *
+ * @return array
+ */
+ public function get_interface_list(string $interface_name): array {
+ //make sure we can return values
+ if (empty($this->classes) || empty($this->interfaces)) {
+ return [];
+ }
+ //check if we have an interface with that name
+ if (!empty($this->interfaces[$interface_name])) {
+ //return the list of classes associated with that interface
+ return $this->interfaces[$interface_name];
+ }
+ //interface is not implemented by any classes
+ return [];
+ }
+
+ /**
+ * Returns a list of all user defined interfaces that have been registered.
+ *
+ * @return array
+ */
+ public function get_interfaces(): array {
+ if (!empty($this->interfaces)) {
+ return $this->interfaces;
+ }
+ return [];
+ }
+
+ /**
+ * The loader is set to private because only the PHP engine should be calling this method
+ *
+ * @param string $class_name The class name that needs to be loaded
+ *
+ * @return bool True if the class is loaded or false when the class is not found
+ * @access private
+ */
+ private function loader($class_name): bool {
+
+ //sanitize the class name
+ $class_name = preg_replace('[^a-zA-Z0-9_]', '', $class_name);
+
+ //find the path using the class_name as the key in the classes array
+ if (isset($this->classes[$class_name])) {
+ //include the class or interface
+ include_once $this->classes[$class_name];
+
+ //return boolean
+ return true;
+ }
+
+ //Smarty has it's own autoloader so reject the request
+ if ($class_name === 'Smarty_Autoloader') {
+ return false;
+ }
+
+ //cache miss
+ self::log(LOG_WARNING, "class '$class_name' not found in cache");
+
+ //set project path using magic dir constant
+ $project_path = dirname(__DIR__, 2);
+
+ //build the search path array
+ $search_path[] = glob($project_path . "/resources/interfaces/" . $class_name . ".php");
+ $search_path[] = glob($project_path . "/resources/traits/" . $class_name . ".php");
+ $search_path[] = glob($project_path . "/resources/classes/" . $class_name . ".php");
+ $search_path[] = glob($project_path . "/*/*/resources/interfaces/" . $class_name . ".php");
+ $search_path[] = glob($project_path . "/*/*/resources/traits/" . $class_name . ".php");
+ $search_path[] = glob($project_path . "/*/*/resources/classes/" . $class_name . ".php");
+
+ //fix class names in the plugins directory prefixed with 'plugin_'
+ if (str_starts_with($class_name, 'plugin_')) {
+ $class_name = substr($class_name, 7);
+ }
+ $search_path[] = glob($project_path . "/core/authentication/resources/classes/plugins/" . $class_name . ".php");
+
+ //collapse all entries to only the matched entry
+ $matches = array_filter($search_path);
+ if (!empty($matches)) {
+ $path = array_pop($matches)[0];
+
+ //include the class, interface, or trait
+ include_once $path;
+
+ //inject the class in to the array
+ $this->classes[$class_name] = $path;
+
+ //update the cache with new classes
+ $this->update_cache();
+
+ //return boolean
+ return true;
+ }
+
+ //send to syslog when debugging
+ self::log(LOG_ERR, "class '$class_name' not found name");
+
+ //return boolean
+ return false;
}
}
diff --git a/resources/classes/base2n.php b/resources/classes/base2n.php
index e3f5eb6bb5..49c6aecaeb 100644
--- a/resources/classes/base2n.php
+++ b/resources/classes/base2n.php
@@ -22,8 +22,7 @@
*
* @package binary-to-text-php
*/
-class base2n
-{
+class base2n {
protected $_chars;
protected $_bitsPerCharacter;
protected $_radix;
@@ -36,21 +35,20 @@ class base2n
/**
* Constructor
*
- * @param integer $bitsPerCharacter Bits to use for each encoded character
- * @param string $chars Base character alphabet
- * @param boolean $caseSensitive To decode in a case-sensitive manner
- * @param boolean $rightPadFinalBits How to encode last character
- * @param boolean $padFinalGroup Add padding to end of encoded output
- * @param string $padCharacter Character to use for padding
+ * @param integer $bitsPerCharacter Bits to use for each encoded character
+ * @param string $chars Base character alphabet
+ * @param boolean $caseSensitive To decode in a case-sensitive manner
+ * @param boolean $rightPadFinalBits How to encode last character
+ * @param boolean $padFinalGroup Add padding to end of encoded output
+ * @param string $padCharacter Character to use for padding
*
* @throws InvalidArgumentException for incompatible parameters
*/
public function __construct(
$bitsPerCharacter,
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
- $caseSensitive = TRUE, $rightPadFinalBits = FALSE,
- $padFinalGroup = FALSE, $padCharacter = '=')
- {
+ $caseSensitive = true, $rightPadFinalBits = false,
+ $padFinalGroup = false, $padCharacter = '=') {
// Ensure validity of $chars
if (!is_string($chars) || ($charLength = strlen($chars)) < 2) {
throw new InvalidArgumentException('$chars must be a string of at least two characters');
@@ -68,7 +66,7 @@ class base2n
$padCharFound = stripos($chars, $padCharacter[0]);
}
- if ($padCharFound !== FALSE) {
+ if ($padCharFound !== false) {
throw new InvalidArgumentException('$padCharacter can not be a member of $chars');
}
}
@@ -94,9 +92,9 @@ class base2n
$radix >>= 1;
throw new InvalidArgumentException(
- '$bitsPerCharacter can not be more than ' . $bitsPerCharacter
- . ' given $chars length of ' . $charLength
- . ' (max radix ' . $radix . ')');
+ '$bitsPerCharacter can not be more than ' . $bitsPerCharacter
+ . ' given $chars length of ' . $charLength
+ . ' (max radix ' . $radix . ')');
} elseif ($bitsPerCharacter > 8) {
// $bitsPerCharacter must not be greater than 8
@@ -106,23 +104,23 @@ class base2n
$radix = 1 << $bitsPerCharacter;
}
- $this->_chars = $chars;
- $this->_bitsPerCharacter = $bitsPerCharacter;
- $this->_radix = $radix;
+ $this->_chars = $chars;
+ $this->_bitsPerCharacter = $bitsPerCharacter;
+ $this->_radix = $radix;
$this->_rightPadFinalBits = $rightPadFinalBits;
- $this->_padFinalGroup = $padFinalGroup;
- $this->_padCharacter = $padCharacter[0];
- $this->_caseSensitive = $caseSensitive;
+ $this->_padFinalGroup = $padFinalGroup;
+ $this->_padCharacter = $padCharacter[0];
+ $this->_caseSensitive = $caseSensitive;
}
/**
* Encode a string
*
- * @param string $rawString Binary data to encode
+ * @param string $rawString Binary data to encode
+ *
* @return string
*/
- public function encode($rawString)
- {
+ public function encode($rawString) {
// Unpack string into an array of bytes
$bytes = unpack('C*', $rawString);
$byteCount = count($bytes);
@@ -132,11 +130,11 @@ class base2n
$bitsRead = 0;
$oldBits = 0;
- $chars = $this->_chars;
- $bitsPerCharacter = $this->_bitsPerCharacter;
+ $chars = $this->_chars;
+ $bitsPerCharacter = $this->_bitsPerCharacter;
$rightPadFinalBits = $this->_rightPadFinalBits;
- $padFinalGroup = $this->_padFinalGroup;
- $padCharacter = $this->_padCharacter;
+ $padFinalGroup = $this->_padFinalGroup;
+ $padCharacter = $this->_padCharacter;
$charsPerByte = 8 / $bitsPerCharacter;
$encodedLength = $byteCount * $charsPerByte;
@@ -159,7 +157,7 @@ class base2n
if ($padFinalGroup) {
// Array of the lowest common multiples of $bitsPerCharacter and 8, divided by 8
- $lcmMap = array(1 => 1, 2 => 1, 3 => 3, 4 => 1, 5 => 5, 6 => 3, 7 => 7, 8 => 1);
+ $lcmMap = [1 => 1, 2 => 1, 3 => 3, 4 => 1, 5 => 5, 6 => 3, 7 => 7, 8 => 1];
$bytesPerGroup = $lcmMap[$bitsPerCharacter];
$pads = $bytesPerGroup * $charsPerByte - ceil((strlen($rawString) % $bytesPerGroup) * $charsPerByte);
$encodedString .= str_repeat($padCharacter, $pads);
@@ -183,7 +181,7 @@ class base2n
$bitsRead += $newBitCount;
if ($oldBitCount) {
- // Bits come from seperate bytes, add $oldBits to $bits
+ // Bits come from separate bytes, add $oldBits to $bits
$bits = ($oldBits << $newBitCount) | $bits;
}
@@ -196,31 +194,31 @@ class base2n
/**
* Decode a string
*
- * @param string $encodedString Data to decode
- * @param boolean $strict Returns NULL if $encodedString contains an undecodable character
+ * @param string $encodedString Data to decode
+ * @param boolean $strict Returns NULL if $encodedString contains an undecodable character
+ *
* @return string
*/
- public function decode($encodedString, $strict = FALSE)
- {
+ public function decode($encodedString, $strict = false) {
if (!$encodedString || !is_string($encodedString)) {
// Empty string, nothing to decode
return '';
}
- $chars = $this->_chars;
- $bitsPerCharacter = $this->_bitsPerCharacter;
- $radix = $this->_radix;
+ $chars = $this->_chars;
+ $bitsPerCharacter = $this->_bitsPerCharacter;
+ $radix = $this->_radix;
$rightPadFinalBits = $this->_rightPadFinalBits;
- $padFinalGroup = $this->_padFinalGroup;
- $padCharacter = $this->_padCharacter;
- $caseSensitive = $this->_caseSensitive;
+ $padFinalGroup = $this->_padFinalGroup;
+ $padCharacter = $this->_padCharacter;
+ $caseSensitive = $this->_caseSensitive;
// Get index of encoded characters
if ($this->_charmap) {
$charmap = $this->_charmap;
} else {
- $charmap = array();
+ $charmap = [];
for ($i = 0; $i < $radix; $i++) {
$charmap[$chars[$i]] = $i;
@@ -293,12 +291,10 @@ class base2n
} elseif ($strict) {
// Unable to decode character; abort
- return NULL;
+ return null;
}
}
return $rawString;
}
}
-
-?>
diff --git a/resources/classes/button.php b/resources/classes/button.php
index 29d56facd9..f5eed5c389 100644
--- a/resources/classes/button.php
+++ b/resources/classes/button.php
@@ -25,123 +25,144 @@
Mark J Crane
*/
- class button {
+class button {
- public static $collapse = 'hide-md-dn';
+ public static $collapse = 'hide-md-dn';
- public static function create($array) {
- global $settings;
+ /**
+ * Creates a button element based on the provided array of attributes.
+ *
+ * @param array $array An array containing button attributes, such as type, name, value, id, label, title, onclick,
+ * etc.
+ *
+ * @return string The created button element as a string.
+ */
+ public static function create($array) {
+ global $settings;
- $button_icons = $settings->get('theme', 'button_icons', 'auto');
- //parse styles into array
- if (!empty($array['style'])) {
- $tmp = explode(';',$array['style']);
- foreach ($tmp as $style) {
- if (!empty($style)) {
- $style = explode(':', $style);
- if (is_array($style) && @sizeof($style) == 2) {
- $styles[trim($style[0])] = trim($style[1]);
- }
- }
- }
- $array['style'] = $styles;
- unset($styles);
- }
- //button: open
- $button = "";
- //link
- if (!empty($array['link'])) {
- $anchor = " $value) {
- if (substr_count($property, 'margin')) {
- $styles .= $property.': '.$value.'; ';
- }
- }
- $anchor .= $styles ? "style=".self::quote($styles)." " : null;
- unset($styles);
- }
- $anchor .= isset($array['disabled']) && $array['disabled'] ? "class='disabled' onclick='return false;' " : null;
- $anchor .= ">";
- $button = $anchor.$button."";
- }
- return $button;
+ }
+ $array['style'] = $styles;
+ unset($styles);
}
-
- private static function quote($value) {
- return substr_count($value, "'") ? '"'.$value.'"' : "'".$value."'";
+ //button: open
+ $button = "";
+ //link
+ if (!empty($array['link'])) {
+ $anchor = " $value) {
+ if (substr_count($property, 'margin')) {
+ $styles .= $property . ': ' . $value . '; ';
+ }
+ }
+ $anchor .= $styles ? "style=" . self::quote($styles) . " " : null;
+ unset($styles);
+ }
+ $anchor .= isset($array['disabled']) && $array['disabled'] ? "class='disabled' onclick='return false;' " : null;
+ $anchor .= ">";
+ $button = $anchor . $button . "";
+ }
+ return $button;
}
+ /**
+ * Quotes a value by surrounding it with single or double quotes based on whether it contains single quotes.
+ *
+ * @param string $value The value to be quoted.
+ *
+ * @return string The quoted value.
+ */
+ private static function quote($value) {
+ return substr_count($value, "'") ? '"' . $value . '"' : "'" . $value . "'";
+ }
+
+ /**
+ * Escapes a URL by removing leading/trailing whitespace and encoding special characters.
+ *
+ * @param string $url The URL to escape.
+ *
+ * @return string The escaped URL.
+ */
+ private static function escape_href(string $url): string {
+ // clear whitespace
+ $url = trim($url);
+
+ return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
+ }
+}
+
/*
//usage
diff --git a/resources/classes/cache.php b/resources/classes/cache.php
index 931f33bdae..5a03624e89 100644
--- a/resources/classes/cache.php
+++ b/resources/classes/cache.php
@@ -1,6 +1,5 @@
location = '/var/cache/fusionpbx';
}
+ /**
+ * Get a specific cache setting from the settings array.
+ *
+ * @param string $subcategory The subcategory of the cache setting to retrieve.
+ *
+ * @return mixed The value of the specified cache setting, or null if it does not exist.
+ */
private function setting($subcategory) {
return $this->settings->get('cache', $subcategory);
}
/**
- * Add a specific item in the cache
- * @var string $key the cache id
- * @var string $value string to be cached
- */
- public function set($key, $value) {
-
- //change the delimiter
- $key = str_replace(":", ".", $key);
-
- //save to memcache
- if ($this->method === "memcache") {
- //connect to event socket
- $esl = event_socket::create();
- if ($esl === false) {
- return false;
- }
-
- //run the memcache
- $command = "memcache set ".$key." ".$value;
- $result = event_socket::api($command);
-
- }
-
- //save to the file cache
- if ($this->method === "file") {
- $result = file_put_contents($this->location . "/" . $key, $value);
- }
-
- //return result
- return $result;
- }
-
- /**
- * Get a specific item from the cache
- * @var string $key cache id
+ * Retrieve the value associated with a given cache key.
+ *
+ * @param string $key The cache key to retrieve. Delimiter is automatically changed from ':' to '.'.
+ *
+ * @return mixed The cached value, or null if it does not exist.
*/
public function get($key) {
//change the delimiter
- $key = str_replace(":", ".", $key);
+ $key = str_replace(":", ".", $key);
//cache method memcache
- if ($this->method === "memcache") {
- // connect to event socket
- $esl = event_socket::create();
- if (!$esl->is_connected()) {
- return false;
- }
-
- //send a custom event
-
- //run the memcache
- $command = "memcache get ".$key;
- $result = event_socket::api($command);
-
+ if ($this->method === "memcache") {
+ // connect to event socket
+ $esl = event_socket::create();
+ if (!$esl->is_connected()) {
+ return false;
}
+ //send a custom event
+
+ //run the memcache
+ $command = "memcache get " . $key;
+ $result = event_socket::api($command);
+
+ }
+
//get the file cache
- if ($this->method === "file") {
- if (file_exists($this->location . "/" . $key)) {
- $result = file_get_contents($this->location . "/" . $key);
- }
+ if ($this->method === "file") {
+ if (file_exists($this->location . "/" . $key)) {
+ $result = file_get_contents($this->location . "/" . $key);
}
+ }
//return result
- return $result ?? null;
+ return $result ?? null;
}
/**
- * Delete a specific item from the cache
- * @var string $key cache id
+ * Set a value in the cache based on the cache type in global default settings.
+ *
+ * Cache location is based on the global default setting for either "memcache" or "file".
+ *
+ * @param string $key The key of the value to set.
+ * @param mixed $value The value to store.
+ *
+ * @return mixed When location is "file" the return value is in bytes written or null. When location is "memcache"
+ * return value is the return value from the switch socket response or false.
+ */
+ public function set($key, $value) {
+
+ //change the delimiter
+ $key = str_replace(":", ".", $key);
+
+ //save to memcache
+ if ($this->method === "memcache") {
+ //connect to event socket
+ $esl = event_socket::create();
+ if ($esl === false) {
+ return false;
+ }
+
+ //run the memcache
+ $command = "memcache set " . $key . " " . $value;
+ $result = event_socket::api($command);
+
+ }
+
+ //save to the file cache
+ if ($this->method === "file") {
+ $result = file_put_contents($this->location . "/" . $key, $value);
+ }
+
+ //return result
+ return $result;
+ }
+
+ /**
+ * Delete a single cache key.
+ *
+ * @param string $key The cache key to delete
+ *
+ * @return bool When cache type is "memcache" false is returned on failure otherwise no value is returned
*/
public function delete($key) {
//debug information
- if ($this->syslog === "true") {
- openlog("fusionpbx", LOG_PID | LOG_PERROR, LOG_USER);
- syslog(LOG_WARNING, "debug: cache: [key: ".$key.", script: ".$_SERVER['SCRIPT_NAME'].", line: ".__line__."]");
- closelog();
- }
+ if ($this->syslog === "true") {
+ openlog("fusionpbx", LOG_PID | LOG_PERROR, LOG_USER);
+ syslog(LOG_WARNING, "debug: cache: [key: " . $key . ", script: " . $_SERVER['SCRIPT_NAME'] . ", line: " . __line__ . "]");
+ closelog();
+ }
//cache method memcache
- if ($this->method === "memcache") {
- //connect to event socket
- $esl = event_socket::create();
- if ($esl === false) {
- return false;
- }
-
- //send a custom event
- $event = "sendevent CUSTOM\n";
- $event .= "Event-Name: CUSTOM\n";
- $event .= "Event-Subclass: fusion::memcache\n";
- $event .= "API-Command: memcache\n";
- $event .= "API-Command-Argument: delete ".$key."\n";
- event_socket::command($event);
-
- //run the memcache
- $command = "memcache delete ".$key;
- $result = event_socket::api($command);
-
+ if ($this->method === "memcache") {
+ //connect to event socket
+ $esl = event_socket::create();
+ if ($esl === false) {
+ return false;
}
+ //send a custom event
+ $event = "sendevent CUSTOM\n";
+ $event .= "Event-Name: CUSTOM\n";
+ $event .= "Event-Subclass: fusion::memcache\n";
+ $event .= "API-Command: memcache\n";
+ $event .= "API-Command-Argument: delete " . $key . "\n";
+ event_socket::command($event);
+
+ //run the memcache
+ $command = "memcache delete " . $key;
+ $result = event_socket::api($command);
+
+ }
+
//cache method file
- if ($this->method === "file") {
- //change the delimiter
- $key = str_replace(":", ".", $key);
+ if ($this->method === "file") {
+ //change the delimiter
+ $key = str_replace(":", ".", $key);
- //connect to event socket
- $esl = event_socket::create();
- if ($esl === false) {
- return false;
- }
-
- //send a custom event
- $event = "sendevent CUSTOM\n";
- $event .= "Event-Name: CUSTOM\n";
- $event .= "Event-Subclass: fusion::file\n";
- $event .= "API-Command: cache\n";
- $event .= "API-Command-Argument: delete ".$key."\n";
- event_socket::command($event);
-
- //remove the local files
- foreach (glob($this->location . "/" . $key) as $file) {
- if (file_exists($file)) {
- unlink($file);
- }
- if (file_exists($file)) {
- unlink($file . ".tmp");
- }
- }
+ //connect to event socket
+ $esl = event_socket::create();
+ if ($esl === false) {
+ return false;
}
+ //send a custom event
+ $event = "sendevent CUSTOM\n";
+ $event .= "Event-Name: CUSTOM\n";
+ $event .= "Event-Subclass: fusion::file\n";
+ $event .= "API-Command: cache\n";
+ $event .= "API-Command-Argument: delete " . $key . "\n";
+ event_socket::command($event);
+
+ //remove the local files
+ foreach (glob($this->location . "/" . $key) as $file) {
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ if (file_exists($file)) {
+ unlink($file . ".tmp");
+ }
+ }
+ }
+
}
/**
- * Delete the entire cache
+ * Flushes the cache based on the current method setting.
+ *
+ * @return string|false The result of the flush operation, or false if an error occurred.
*/
public function flush() {
//debug information
- if ($this->syslog === "true") {
- openlog("fusionpbx", LOG_PID | LOG_PERROR, LOG_USER);
- syslog(LOG_WARNING, "debug: cache: [flush: all, script: ".$_SERVER['SCRIPT_NAME'].", line: ".__line__."]");
- closelog();
- }
+ if ($this->syslog === "true") {
+ openlog("fusionpbx", LOG_PID | LOG_PERROR, LOG_USER);
+ syslog(LOG_WARNING, "debug: cache: [flush: all, script: " . $_SERVER['SCRIPT_NAME'] . ", line: " . __line__ . "]");
+ closelog();
+ }
//check for apcu extension
- if (function_exists('apcu_enabled') && apcu_enabled()) {
- //flush everything
- apcu_clear_cache();
- }
+ if (function_exists('apcu_enabled') && apcu_enabled()) {
+ //flush everything
+ apcu_clear_cache();
+ }
//remove the autoloader file cache
- if (file_exists(sys_get_temp_dir() . '/' . auto_loader::CLASSES_FILE)) {
- @unlink(sys_get_temp_dir() . '/' . auto_loader::CLASSES_FILE);
- }
+ if (file_exists(sys_get_temp_dir() . '/' . auto_loader::CLASSES_FILE)) {
+ @unlink(sys_get_temp_dir() . '/' . auto_loader::CLASSES_FILE);
+ }
//cache method memcache
- if ($this->method === "memcache") {
- // connect to event socket
- $esl = event_socket::create();
- if ($esl === false) {
- return false;
- }
-
- //send a custom event
- $event = "sendevent CUSTOM\n";
- $event .= "Event-Name: CUSTOM\n";
- $event .= "Event-Subclass: fusion::memcache\n";
- $event .= "API-Command: memcache\n";
- $event .= "API-Command-Argument: flush\n";
- event_socket::command($event);
-
- //run the memcache
- $command = "memcache flush";
- $result = event_socket::api($command);
-
+ if ($this->method === "memcache") {
+ // connect to event socket
+ $esl = event_socket::create();
+ if ($esl === false) {
+ return false;
}
+ //send a custom event
+ $event = "sendevent CUSTOM\n";
+ $event .= "Event-Name: CUSTOM\n";
+ $event .= "Event-Subclass: fusion::memcache\n";
+ $event .= "API-Command: memcache\n";
+ $event .= "API-Command-Argument: flush\n";
+ event_socket::command($event);
+
+ //run the memcache
+ $command = "memcache flush";
+ $result = event_socket::api($command);
+
+ }
+
//cache method file
- if ($this->method === "file") {
- // connect to event socket
- $esl = event_socket::create();
- if ($esl === false) {
- return false;
- }
-
- //send a custom event
- $event = "sendevent CUSTOM\n";
- $event .= "Event-Name: CUSTOM\n";
- $event .= "Event-Subclass: fusion::file\n";
- $event .= "API-Command: cache\n";
- $event .= "API-Command-Argument: flush\n";
- event_socket::command($event);
-
- //remove the cache
- recursive_delete($this->location);
-
- //set message
- $result = '+OK cache flushed';
+ if ($this->method === "file") {
+ // connect to event socket
+ $esl = event_socket::create();
+ if ($esl === false) {
+ return false;
}
+ //send a custom event
+ $event = "sendevent CUSTOM\n";
+ $event .= "Event-Name: CUSTOM\n";
+ $event .= "Event-Subclass: fusion::file\n";
+ $event .= "API-Command: cache\n";
+ $event .= "API-Command-Argument: flush\n";
+ event_socket::command($event);
+
+ //remove the cache
+ recursive_delete($this->location);
+
+ //set message
+ $result = '+OK cache flushed';
+ }
+
//return result
- return $result;
+ return $result;
}
}
-
-?>
diff --git a/resources/classes/captcha.php b/resources/classes/captcha.php
index 40b6eca03b..d6a976d10c 100644
--- a/resources/classes/captcha.php
+++ b/resources/classes/captcha.php
@@ -32,20 +32,32 @@
class captcha {
/**
- * Called when the object is created
- */
+ * Called when the object is created
+ */
public $code;
/**
- * Class constructor
- */
+ * Class constructor
+ */
public function __construct() {
}
/**
- * Create the captcha image
- * @var string $code
+ * Returns a Base64 encoded version of the CAPTCHA image.
+ *
+ * @return string The Base64 encoded CAPTCHA image data.
+ */
+ public function image_base64() {
+ return base64_encode($this->image_captcha());
+ }
+
+ /**
+ * Generates a CAPTCHA image.
+ *
+ * Requires the object property code for the text to create
+ *
+ * @return string The CAPTCHA image buffer.
*/
public function image_captcha() {
@@ -54,25 +66,25 @@ class captcha {
$text = $this->code;
// Set the font path
- $font_path = $_SERVER["DOCUMENT_ROOT"]."/resources/captcha/fonts";
+ $font_path = $_SERVER["DOCUMENT_ROOT"] . "/resources/captcha/fonts";
// Array of fonts
//$fonts[] = 'ROUGD.TTF';
//$fonts[] = 'Zebra.ttf';
//$fonts[] = 'hanshand.ttf';
- $fonts = glob($font_path.'/*.[tT][tT][fF]');
+ $fonts = glob($font_path . '/*.[tT][tT][fF]');
//print_r($fonts);
//exit;
// Randomize the fonts
srand();
- $random = (rand()%count($fonts));
+ $random = (rand() % count($fonts));
//$font = $font_path.'/'.$fonts[$random];
$font = $fonts[$random];
// Set the font size
$font_size = 16;
- if(@$_GET['fontsize']) {
+ if (@$_GET['fontsize']) {
$font_size = $_GET['fontsize'];
}
@@ -109,15 +121,14 @@ class captcha {
}
/**
- * return the image in base64
- */
- public function image_base64() {
- return base64_encode($this->image_captcha());
- }
-
- /**
- * Get the image size
- * @var string $value string image size
+ * Calculates the bounding box of a text in an image.
+ *
+ * @param int $size The size of the font.
+ * @param float $angle The angle of rotation.
+ * @param string $font The path to the font file.
+ * @param string $text The text to be rendered.
+ *
+ * @return array An array containing the bounding box coordinates (x, y, w, h).
*/
private function image_size($size, $angle, $font, $text) {
$dummy = imagecreate(1, 1);
@@ -135,5 +146,3 @@ $captcha->code = 'abcdefg';
$image_base64 = $captcha->base64();
echo "\n";
*/
-
-?>
diff --git a/resources/classes/command_option.php b/resources/classes/command_option.php
index 622e3b8974..573758be55 100644
--- a/resources/classes/command_option.php
+++ b/resources/classes/command_option.php
@@ -28,6 +28,7 @@
/**
* Container object for creating command line options when creating a service
+ *
* @author Tim Fry
*/
class command_option {
@@ -52,9 +53,11 @@ class command_option {
}
/**
- * A factory method to create a new command_option
- * @param type $options
- * @return command_option
+ * Creates a new instance of CommandOption with automatically assigned properties.
+ *
+ * @param array $options Key/Value pairs to assign as properties on the new instance.
+ *
+ * @return command_option Returns a populated instance of command_option.
*/
public static function new(...$options): command_option {
$obj = new command_option();
@@ -67,6 +70,15 @@ class command_option {
}
// used to parse object values when created
+
+ /**
+ * Recursively parses the provided options array and applies its values to the given object.
+ *
+ * @param mixed $obj The object whose properties will be updated with the parsed options
+ * @param array $options The associative array containing the options to parse and apply
+ *
+ * @return void This method does not return a value, it updates the provided object instead.
+ */
private static function parse_options($obj, $options) {
foreach ($options as $key => $value) {
if (is_array($value)) {
@@ -81,9 +93,63 @@ class command_option {
}
}
+ /**
+ * Appends the callback function to the array of existing callback functions
+ *
+ * @param string|null $function When function param is set, the callback function will be appended to the list of
+ * functions. When called without a param, the array will be returned of current
+ * callbacks.
+ *
+ * @return $this|array Returns the array of callbacks if no parameters passed or this object when appending a
+ * callback
+ */
+ public function callback(?string $function = null) {
+ if ($function !== null) {
+ $this->functions += [$function];
+ return $this;
+ }
+ return $this->functions;
+ }
+
+ /**
+ * Appends the callback function to the array of existing callback functions
+ *
+ * @param string|null $function When function param is set, the callback function will be appended to the list of
+ * functions. When called without a param, the array will be returned of current
+ * callbacks.
+ *
+ * @return $this|array Returns the array of callbacks if no parameters passed or this object when appending a
+ * callback
+ */
+ public function function_append(?string $function = null) {
+ if ($function !== null) {
+ $this->functions += [$function];
+ return $this;
+ }
+ return $this->functions;
+ }
+
+ /**
+ * Converts the current object to an array.
+ *
+ * @return array The array representation of the current object, containing
+ * information about options and functions.
+ */
+ public function to_array(): array {
+ $array['short_option'] = $this->short_option();
+ $array['long_option'] = $this->long_option();
+ $array['description'] = $this->description();
+ $array['short_description'] = $this->short_description();
+ $array['long_description'] = $this->long_description();
+ $array['functions'] = $this->functions();
+ return $array;
+ }
+
/**
* Sets or returns the short option value
+ *
* @param string|null $short_option
+ *
* @return $this
*/
public function short_option(?string $short_option = null) {
@@ -96,7 +162,9 @@ class command_option {
/**
* Sets or returns the long option value
+ *
* @param string|null $long_option
+ *
* @return $this
*/
public function long_option(?string $long_option = null) {
@@ -109,7 +177,9 @@ class command_option {
/**
* Set the general description
+ *
* @param string|null $description
+ *
* @return $this
*/
public function description(?string $description = null) {
@@ -122,7 +192,10 @@ class command_option {
/**
* Sets or returns the short_description. If short_description is empty then the short_option is used as a default.
- * @param string|null $short_description When parameter is null, it returns the currently set value. When not null the short description is set to the passed value.
+ *
+ * @param string|null $short_description When parameter is null, it returns the currently set value. When not null
+ * the short description is set to the passed value.
+ *
* @return $this
*/
public function short_description(?string $short_description = null) {
@@ -145,8 +218,11 @@ class command_option {
/**
* Sets or returns the long_description. If long_description is empty then the long_option is used as a default.
- * @param string|null $long_description When parameter is null, it returns the currently set value. When not null the long description is set to the passed value.
- * @return $this
+ *
+ * @param string|null $long_description When parameter is null, it returns the currently set value. When not null
+ * the long description is set to the passed value.
+ *
+ * @return self|string
*/
public function long_description(?string $long_description = null) {
if ($long_description !== null) {
@@ -167,9 +243,13 @@ class command_option {
}
/**
- * Adds an array of callback functions replacing the existing callback functions
- * @param array|null $functions
- * @return $this
+ * Sets or retrieves the array of callback functions
+ *
+ * @param array|null $functions When functions param is set, the array will be assigned to the list of callbacks.
+ * When called without a parameter, the current array of callbacks will be returned.
+ *
+ * @return $this|array Returns the array of callbacks if no parameters passed or this object when setting a new
+ * array
*/
public function functions(?array $functions = null) {
if ($functions !== null) {
@@ -178,46 +258,6 @@ class command_option {
}
return $this->functions;
}
-
- /**
- * Appends the callback function to the array of existing callback functions
- * @param string|null $function When function param is set, the callback function will be appended to the list of functions. When called without a param, the array will be returned of current callbacks.
- * @return $this|array Returns the array of callbacks if no parameters passed or this object when appending a callback
- */
- public function callback(?string $function = null) {
- if ($function !== null) {
- $this->functions += [$function];
- return $this;
- }
- return $this->functions;
- }
-
- /**
- * Appends the callback function to the array of existing callback functions
- * @param string|null $function
- * @return $this
- */
- public function function_append(?string $function = null) {
- if ($function !== null) {
- $this->functions += [$function];
- return $this;
- }
- return $this->functions;
- }
-
- /**
- * Returns the array structure required for service
- * @return array
- */
- public function to_array(): array {
- $array['short_option'] = $this->short_option();
- $array['long_option'] = $this->long_option();
- $array['description'] = $this->description();
- $array['short_description'] = $this->short_description();
- $array['long_description'] = $this->long_description();
- $array['functions'] = $this->functions();
- return $array;
- }
}
/* Examples
diff --git a/resources/classes/config.php b/resources/classes/config.php
index 80f8aea0bb..52ede00e29 100644
--- a/resources/classes/config.php
+++ b/resources/classes/config.php
@@ -2,39 +2,48 @@
/**
* config class loads configuration from the file system
- * @param string $db_type Type of database
- * @param string $db_driver Alias of type
- * @param string $db_host Host to connect to
- * @param string $db_path Path of the database if it is file system based
- * @param string $db_file File name of the database if it is file system based
- * @param string $db_port Port to connect to
- * @param string $db_name Name of the database
- * @param string $db_sslmode SSL Mode to use
- * @param string $db_cert_authority The certificate authority
- * @param string $db_secure If the database is using a secure connection
- * @param string $db_username Username credentials to connect with
- * @param string $db_password Password credentials to connect with
- * @param string $config_path Configuration path currently in use
- * @param string $config_file Configuration file currently in use
+ *
+ * @param string $db_type Type of database
+ * @param string $db_driver Alias of type
+ * @param string $db_host Host to connect to
+ * @param string $db_path Path of the database if it is file system based
+ * @param string $db_file File name of the database if it is file system based
+ * @param string $db_port Port to connect to
+ * @param string $db_name Name of the database
+ * @param string $db_sslmode SSL Mode to use
+ * @param string $db_cert_authority The certificate authority
+ * @param string $db_secure If the database is using a secure connection
+ * @param string $db_username Username credentials to connect with
+ * @param string $db_password Password credentials to connect with
+ * @param string $config_path Configuration path currently in use
+ * @param string $config_file Configuration file currently in use
* @param string $config_path_and_filename Full path and configuration file currently in use
- * @internal the @param statements are used because they match the magic __get function that allows those to be accessed publicly
+ *
+ * @internal the @param statements are used because they match the magic __get function that allows those to be
+ * accessed publicly
*/
final class config {
// Full path and filename of config.conf
- private $file;
-
- // The internal array that holds the configuration in the config.conf file
- private $configuration;
-
/**
* Configuration object used to hold a single instance
+ *
* @var array
*/
public static $config = null;
+ // The internal array that holds the configuration in the config.conf file
+ private $file;
+ private $configuration;
+
/**
- * Loads the framework configuration file
+ * Initializes a new instance of the class with an optional configuration file.
+ *
+ * If no file is provided, it will attempt to locate one using the `find()` method.
+ *
+ * @param string $file The path to the configuration file (optional).
+ *
+ * @return void
*/
public function __construct(string $file = '') {
@@ -60,78 +69,45 @@ final class config {
}
/**
- * Magic method to allow backward compatibility for variables such as db_type.
- *
This will allow using config object with the syntax of:
- * $config = new config();
- * $db_type = $config->db_type;
- *
Note:
- * The InvalidArgumentException is thrown if there is no such variable accessed such as:
- * $config = new config();
- * $db_function = $config->db_function();
- *
- *
This is ensure that any invalid code is detected and fixed.
- * @param string $name Name of the object property
- * @return string Returns the value as a string
+ * Finds and returns the path of the configuration file.
+ *
+ * Find tries to look for the config.conf file in the following locations: /etc/fusionpbx, /usr/local/etc/fusionpbx.
+ * When unsuccessful it will then search for the config.php file in the same locations. Last, find will search the
+ * SystemDrive folder for Windows operating systems trying first for config.conf and then config.php.
+ *
+ * @return string path to the configuration file
*/
- public function __get(string $name): string {
- switch($name) {
- case 'db_type':
- case 'db_driver':
- return $this->configuration['database.0.type'] ?? '';
- case 'db_path':
- case 'path':
- return $this->configuration['database.0.path'] ?? '';
- case 'db_host':
- return $this->configuration['database.0.host'] ?? '';
- case 'db_port':
- return $this->configuration['database.0.port'] ?? '';
- case 'db_name':
- return $this->configuration['database.0.name'] ?? '';
- case 'db_sslmode':
- return $this->configuration['database.0.sslmode'] ?? 'prefer';
- case 'db_cert_authority':
- return $this->configuration['database.0.cert_authority'] ?? '';
- case 'db_secure':
- return $this->configuration['database.0.secure'] ?? 'false';
- case 'db_username':
- case 'username':
- return $this->configuration['database.0.username'] ?? '';
- case 'db_password':
- case 'password':
- return $this->configuration['database.0.password'] ?? '';
- case 'db_file':
- return $this->configuration['database.0.file'] ?? '';
- case 'config_path':
- return $this->path();
- case 'config_filename':
- return $this->filename();
- case 'config_path_and_filename':
- case 'config_file':
- return $this->path_and_filename();
- default:
- if (property_exists($this, $name)) {
- return $this->{$name};
- }
- elseif (array_key_exists($name, $this->configuration)) {
- return $this->configuration[$name];
- }
+ public static function find(): string {
+ //define the file variable
+ $file = "";
+
+ //find the file
+ if (file_exists("/etc/fusionpbx/config.conf")) {
+ $file = "/etc/fusionpbx/config.conf";
+ } elseif (file_exists("/usr/local/etc/fusionpbx/config.conf")) {
+ $file = "/usr/local/etc/fusionpbx/config.conf";
+ } elseif (file_exists("/etc/fusionpbx/config.php")) {
+ $file = "/etc/fusionpbx/config.php";
+ } elseif (file_exists("/usr/local/etc/fusionpbx/config.php")) {
+ $file = "/usr/local/etc/fusionpbx/config.php";
+ } elseif (file_exists(getenv('SystemDrive') . DIRECTORY_SEPARATOR . 'ProgramData' . DIRECTORY_SEPARATOR . 'fusionpbx' . DIRECTORY_SEPARATOR . 'config.conf')) {
+ $file = getenv('SystemDrive') . DIRECTORY_SEPARATOR . 'ProgramData' . DIRECTORY_SEPARATOR . 'fusionpbx' . DIRECTORY_SEPARATOR . 'config.conf';
+ } elseif (file_exists(dirname(__DIR__, 2) . "/resources/config.php")) {
+ //use the current web directory to find it as a last resort
+ $file = "/var/www/fusionpbx/resources/config.php";
}
- return "";
+ return $file;
}
/**
- * Returns the string representation of the configuration file
- * @return string configuration
+ * Reads and parses the configuration file.
+ *
+ * If the file has a .php extension, it will be included as PHP code. Otherwise,
+ * it will be parsed using the parse_ini_file function.
+ * The old properties from config.php are converted to the new standard.
+ *
+ * @return void
*/
- public function __toString(): string {
- $string_builder = "";
- foreach ($this->configuration as $key => $value) {
- $string_builder .= "$key = '$value'\n";
- }
- return $string_builder;
- }
-
- // loads the config.conf file
public function read() {
//check if include is needed
@@ -183,27 +159,39 @@ final class config {
//remove from the global namespace
unset($db_type, $db_host, $db_port, $db_name, $db_username, $db_password, $db_sslmode, $db_secure, $db_cert_authority);
- }
- else {
+ } else {
//save the loaded and parsed conf file to the object
$this->configuration = parse_ini_file($this->file);
}
}
- // set project paths if not already defined
+ // loads the config.conf file
+
+ /**
+ * Defines project paths and sets internal server variables
+ *
+ * @return void
+ */
private function define_project_paths() {
// Load the document root
$doc_root = $this->get('document.root', '/var/www/fusionpbx');
$doc_path = $this->get('document.path', '');
//set the server variables and define project path constant
if (!empty($doc_path)) {
- if (!defined('PROJECT_PATH')) { define("PROJECT_PATH", $doc_path); }
- if (!defined('PROJECT_ROOT')) { define("PROJECT_ROOT", $doc_root.'/'.$doc_path); }
- }
- else {
- if (!defined('PROJECT_PATH')) { define("PROJECT_PATH", ''); }
- if (!defined('PROJECT_ROOT')) { define("PROJECT_ROOT", $doc_root); }
+ if (!defined('PROJECT_PATH')) {
+ define("PROJECT_PATH", $doc_path);
+ }
+ if (!defined('PROJECT_ROOT')) {
+ define("PROJECT_ROOT", $doc_root . '/' . $doc_path);
+ }
+ } else {
+ if (!defined('PROJECT_PATH')) {
+ define("PROJECT_PATH", '');
+ }
+ if (!defined('PROJECT_ROOT')) {
+ define("PROJECT_ROOT", $doc_root);
+ }
}
// internal definitions to the framework
@@ -217,41 +205,15 @@ final class config {
set_include_path(PROJECT_ROOT);
}
- /**
- * Find the path to the config.conf file
- * @var string $config_path - full path to the config.php file
- */
- public static function find(): string {
- //define the file variable
- $file = "";
-
- //find the file
- if (file_exists("/etc/fusionpbx/config.conf")) {
- $file = "/etc/fusionpbx/config.conf";
- }
- elseif (file_exists("/usr/local/etc/fusionpbx/config.conf")) {
- $file = "/usr/local/etc/fusionpbx/config.conf";
- }
- elseif (file_exists("/etc/fusionpbx/config.php")) {
- $file = "/etc/fusionpbx/config.php";
- }
- elseif (file_exists("/usr/local/etc/fusionpbx/config.php")) {
- $file = "/usr/local/etc/fusionpbx/config.php";
- }
- elseif (file_exists(getenv('SystemDrive') . DIRECTORY_SEPARATOR . 'ProgramData' . DIRECTORY_SEPARATOR . 'fusionpbx' . DIRECTORY_SEPARATOR . 'config.conf')) {
- $file = getenv('SystemDrive') . DIRECTORY_SEPARATOR . 'ProgramData' . DIRECTORY_SEPARATOR . 'fusionpbx' . DIRECTORY_SEPARATOR . 'config.conf';
- }
- elseif (file_exists(dirname(__DIR__, 2) . "/resources/config.php")) {
- //use the current web directory to find it as a last resort
- $file = "/var/www/fusionpbx/resources/config.php";
- }
- return $file;
- }
+ // set project paths if not already defined
/**
* Get a configuration value using a key in the configuration file
- * @param string $key Match key on the left hand side of the '=' in the config file. If $key is null the default value is returned
+ *
+ * @param string $key Match key on the left hand side of the '=' in the config file. If $key is null
+ * the default value is returned
* @param string|null $default_value if no matching key is found, then this value will be returned
+ *
* @return string|null returns a value in the config.conf file or an empty string
*/
public function get(string $key, ?string $default_value = ''): ?string {
@@ -262,48 +224,103 @@ final class config {
}
/**
- * Returns the config path or an empty string
- * @return string
+ * Magic method to allow backward compatibility for variables such as db_type.
+ *
This will allow using config object with the syntax of:
+ * $config = new config();
+ * $db_type = $config->db_type;
+ *
Note:
+ * The InvalidArgumentException is thrown if there is no such variable accessed such as:
+ * $config = new config();
+ * $db_function = $config->db_function();
+ *
+ *
This is ensure that any invalid code is detected and fixed.
+ *
+ * @param string $name Name of the object property
+ *
+ * @return string Returns the value as a string
+ */
+ public function __get(string $name): string {
+ switch ($name) {
+ case 'db_type':
+ case 'db_driver':
+ return $this->configuration['database.0.type'] ?? '';
+ case 'db_path':
+ case 'path':
+ return $this->configuration['database.0.path'] ?? '';
+ case 'db_host':
+ return $this->configuration['database.0.host'] ?? '';
+ case 'db_port':
+ return $this->configuration['database.0.port'] ?? '';
+ case 'db_name':
+ return $this->configuration['database.0.name'] ?? '';
+ case 'db_sslmode':
+ return $this->configuration['database.0.sslmode'] ?? 'prefer';
+ case 'db_cert_authority':
+ return $this->configuration['database.0.cert_authority'] ?? '';
+ case 'db_secure':
+ return $this->configuration['database.0.secure'] ?? 'false';
+ case 'db_username':
+ case 'username':
+ return $this->configuration['database.0.username'] ?? '';
+ case 'db_password':
+ case 'password':
+ return $this->configuration['database.0.password'] ?? '';
+ case 'db_file':
+ return $this->configuration['database.0.file'] ?? '';
+ case 'config_path':
+ return $this->path();
+ case 'config_filename':
+ return $this->filename();
+ case 'config_path_and_filename':
+ case 'config_file':
+ return $this->path_and_filename();
+ default:
+ if (property_exists($this, $name)) {
+ return $this->{$name};
+ } elseif (array_key_exists($name, $this->configuration)) {
+ return $this->configuration[$name];
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Returns the directory path of the configuration file.
+ *
+ * @return string the directory path of the configuration file
*/
public function path(): string {
return dirname($this->file);
}
/**
- * Returns the file name only of the configuration file
- * @return string
+ * Returns the filename of the processed file.
+ *
+ * @return string filename
*/
public function filename(): string {
return basename($this->file);
}
/**
- * Returns the path and the file name
- * @return string
+ * Returns the file's path and filename.
+ *
+ * @return string path and filename of the file
*/
public function path_and_filename(): string {
return $this->file;
}
/**
- * Returns if the config class has a loaded configuration or not
- * @return bool True if configuration has loaded and false if it is empty
- */
- public function is_empty(): bool {
- return count($this->configuration) === 0;
- }
-
- /**
- * Returns the array of configuration settings
- * @return array
- */
- public function configuration(): array {
- return $this->configuration;
- }
-
- /**
- * Ensures the configuration file is loaded only once
- * @return config
+ * Returns a singleton instance of the configuration object
+ *
+ * If no file path is provided, loads the default configuration.
+ * Otherwise, attempts to load the specified file and returns the result.
+ *
+ * @param string $file The optional file path to load (default: ''). Note: If the configuration file is already
+ * loaded, the file provided will be ignored.
+ *
+ * @return config The loaded or default configuration object
*/
public static function load(string $file = ''): config {
if (self::$config === null) {
@@ -311,6 +328,37 @@ final class config {
}
return self::$config;
}
+
+ /**
+ * Returns the string representation of the configuration file
+ *
+ * @return string configuration
+ */
+ public function __toString(): string {
+ $string_builder = "";
+ foreach ($this->configuration as $key => $value) {
+ $string_builder .= "$key = '$value'\n";
+ }
+ return $string_builder;
+ }
+
+ /**
+ * Checks if the configuration is empty.
+ *
+ * @return bool true if the configuration is empty, false otherwise
+ */
+ public function is_empty(): bool {
+ return count($this->configuration) === 0;
+ }
+
+ /**
+ * Returns the current application configuration
+ *
+ * @return array configuration data
+ */
+ public function configuration(): array {
+ return $this->configuration;
+ }
}
/*
diff --git a/resources/classes/database.php b/resources/classes/database.php
index 8cf1f64288..8c2857097d 100644
--- a/resources/classes/database.php
+++ b/resources/classes/database.php
@@ -25,100 +25,110 @@
Luis Daniel Lucio Quiroz
*/
-//define the database class
+/**
+ * Database class
+ *
+ * @property $name Alias of app_name
+ */
class database {
/**
*
- */
+ */
const TABLE_PREFIX = "v_";
-
+ /**
+ * Stores the application built from the app_config files.
+ *
+ * @see $apps
+ * @access private
+ * @var array
+ */
+ private static $apps = [];
+ /**
+ * Singleton type class
+ *
+ * @var database
+ */
+ private static $database;
/**
* Database connection
+ *
* @access private
* @var PDO object
*/
public $db;
-
/**
* Driver to use.
+ *
* @access public
* @var string Can be pgsql, mysql, sqlite, odbc
*/
public $driver;
-
/**
* Alias of driver.
+ *
* @access public
+ * @see $driver
* @var string Can be pgsql, mysql, sqlite, odbc
- * @see $driver
*/
public $type;
-
/**
* Host for database connection
+ *
* @access public
* @var string host name or IP address.
*/
public $host;
-
/**
* Port number
+ *
* @access public
* @var int 1025 - 65534
*/
public $port;
-
/**
* Database name
+ *
* @access public
* @var string
*/
public $db_name;
-
/**
* Database security
+ *
* @access public
* @var boolean
*/
public $db_secure;
-
/**
* Specifies the file name of the client SSL certificate
+ *
* @access public
* @var string full path
*/
public $db_cert_authority;
-
/**
* Username used to connect
+ *
* @access public
* @var string
*/
public $username;
-
/**
* Password used to connect
+ *
* @access public
* @var string
*/
public $password;
-
/**
* Full path to file name.
+ *
* @access public
* @var string full path to file name
*/
- public $path;
-
- /**
- * Table name.
- * @access private
- * @var string sanitized
- */
- private $table;
-
- /**
+ public $path; //array
+/**
* Where clause(s) of an SQL statement.
*
Array of arrays must be passed with each having the
* following keys:
@@ -127,17 +137,18 @@ class database {
*
+ *
* @access public
+ * @see $order_by
* @var array Two dimensional array of key value pairs
- * @see $order_by
*/
public $where; //array
-
- /**
+/**
* Order By clause(s) of an SQL statement.
*
Array of arrays must be passed with each having the
* following keys:
@@ -146,155 +157,153 @@ class database {
*
+ *
* @access private
+ * @see $where
* @var array Two dimensional array of key value pairs
- * @see $where
*/
- public $order_by; //array
-
+ public $order_by;
/**
* Ascending or Descending order.
+ *
* @var string
* @access public
*/
public $order_type;
-
/**
* Numerical value to limit returned results.
+ *
* @var int Used for 'LIMIT' in SQL statement.
* @access public
*/
public $limit;
-
/**
* Numerical value to offset returned results.
+ *
* @var int Used for 'OFFSET' in SQL statement.
* @access public
*/
public $offset;
-
/**
*
Array of fields.
*
Fields are specified in 'name'=>'value' format.
*
Used by {@link database::add() } and {@link database::update() }
+ *
* @access public
+ * @see database::add()
+ * @see database::update()
* @var array Array of columns
- * @see database::add()
- * @see database::update()
*/
public $fields;
-
/**
* Unknown property
+ *
* @var unknown
* @access public
*/
public $count;
-
/**
* Unknown property
+ *
* @var unknown
* @access public
*/
public $sql;
-
- /**
- *
Stores the result from the most recent query. The type will be based on what was requested.
- *
NOTE: If an error occurred on the last query the result is set to an empty string.
- * @var mixed
- */
- private $result;
-
- /**
- * Stores the application built from the app_config files.
- * @var array
- * @see $apps
- * @access private
- */
- private static $apps = [];
-
/**
* Stores the application name making the request.
+ *
* @var string App name making database request.
* @access public
*/
public $name;
-
/**
* Stores the application name making the request.
- * @var string App name making database request.
- * @see $app_uuid
+ *
+ * @see $app_uuid
* @access public
+ * @var string App name making database request.
*/
public $app_name;
-
/**
* Stores the application UUID making the request.
- * @var string
- * @see $app_name
+ *
+ * @see $app_name
* @access public
+ * @var string
*/
public $app_uuid;
-
/**
*
Stores the domain UUID making the request.
*
This is defaulted to the Session domain UUID.
+ *
* @access public
- * @uses $this->domain_uuid Default value upon object creation
+ * @uses $this->domain_uuid Default value upon object creation
* @var string Domain UUID making request.
*/
public $domain_uuid;
-
/**
*
Stores the user UUID making the request.
*
This is defaulted to the Session domain UUID.
+ *
* @access public
- * @uses $this->user_uuid Default value upon object creation
+ * @uses $this->user_uuid Default value upon object creation
* @var string Domain UUID making request.
*/
public $user_uuid;
-
/**
*
Message for the query results.
+ *
* @var array Contains the message array after a query
* @access private
*/
public $message;
-
+ /**
+ * SSL Mode used to connect to the database
+ *
+ * @var string prefer or verify-ca. Default is 'prefer'
+ */
+ public $ssl_mode;
+ /**
+ * Table name.
+ *
+ * @access private
+ * @var string sanitized
+ */
+ private $table;
+ /**
+ *
Stores the result from the most recent query. The type will be based on what was requested.
+ *
NOTE: If an error occurred on the last query the result is set to an empty string.
+ *
+ * @var mixed
+ */
+ private $result;
/**
* Config object used to get the database connection params
+ *
* @var config
*/
private $config;
/**
- * SSL Mode used to connect to the database
- * @var string prefer or verify-ca. Default is 'prefer'
- */
- public $ssl_mode;
-
- /**
- * Singleton type class
- * @var database
- */
- private static $database;
-
- /**
- * Called when the object is created
- * @param array $params Optional
+ * Constructor for the class.
+ *
+ * This method initializes the object with setting_array and session data.
+ *
+ * @param array $params An optional array of settings to override default values. Defaults to [].
*/
public function __construct(array $params = []) {
//handle the config object
if (isset($params['config'])) {
$config = $params['config'];
- }
- else {
- $config = new config();
+ } else {
+ //use singleton config
+ $config = config::load();
}
//driver and type point to the same value
@@ -334,14 +343,366 @@ class database {
}
}
+ /**
+ *
Connect to the database.
+ *
Database driver must be set before calling connect.
+ *
For types other than sqlite. Execution will stop on failure.
+ *
+ * @depends database::driver Alias of database::type.
+ *
+ */
+ public function connect() {
+
+ //get the database connection settings
+ //$db_type = $conf['database.0.type'];
+ //$db_host = $conf['database.0.host'];
+ //$db_port = $conf['database.0.port'];
+ //$db_name = $conf['database.0.name'];
+ //$db_username = $conf['database.0.username'];
+ //$db_password = $conf['database.0.password'];
+
+ //debug info
+ //echo "db type:".$db_type."\n";
+ //echo "db host:".$db_host."\n";
+ //echo "db port:".$db_port."\n";
+ //echo "db name:".$db_name."\n";
+ //echo "db username:".$db_username."\n";
+ //echo "db password:".$db_password."\n";
+ //echo "db path:".$db_path."\n";
+ //echo "\n";
+
+ //set defaults
+ if (!isset($this->driver) && isset($db_type)) {
+ $this->driver = $db_type;
+ }
+ if (!isset($this->type) && isset($db_type)) {
+ $this->type = $db_type;
+ }
+ if (!isset($this->host) && isset($db_host)) {
+ $this->host = $db_host;
+ }
+ if (!isset($this->port) && isset($db_port)) {
+ $this->port = $db_port;
+ }
+ if (!isset($this->db_name) && isset($db_name)) {
+ $this->db_name = $db_name;
+ }
+ if (!isset($this->db_secure) && isset($db_secure)) {
+ $this->db_secure = $db_secure;
+ } else {
+ $this->db_secure = false;
+ }
+ if (!isset($this->username) && isset($db_username)) {
+ $this->username = $db_username;
+ }
+ if (!isset($this->password) && isset($db_password)) {
+ $this->password = $db_password;
+ }
+ if (!isset($this->path) && isset($db_path)) {
+ $this->path = $db_path;
+ }
+
+ if ($this->driver == "sqlite") {
+ if (empty($this->db_name)) {
+ $server_name = $_SERVER["SERVER_NAME"];
+ $server_name = str_replace("www.", "", $server_name);
+ $db_name_short = $server_name;
+ $this->db_name = $server_name . '.db';
+ } else {
+ $db_name_short = $this->db_name;
+ }
+ $this->path = realpath($this->path);
+ if (file_exists($this->path . '/' . $this->db_name)) {
+ //connect to the database
+ $this->db = new PDO('sqlite:' . $this->path . '/' . $this->db_name); //sqlite 3
+ //PRAGMA commands
+ $this->db->query('PRAGMA foreign_keys = ON;');
+ $this->db->query('PRAGMA journal_mode = wal;');
+ //add additional functions to SQLite so that they are accessible inside SQL
+ //bool PDO::sqliteCreateFunction ( string function_name, callback callback [, int num_args] )
+ $this->db->sqliteCreateFunction('md5', 'php_md5', 1);
+ $this->db->sqliteCreateFunction('unix_timestamp', 'php_unix_timestamp', 1);
+ $this->db->sqliteCreateFunction('now', 'php_now', 0);
+ $this->db->sqliteCreateFunction('sqlitedatatype', 'php_sqlite_data_type', 2);
+ $this->db->sqliteCreateFunction('strleft', 'php_left', 2);
+ $this->db->sqliteCreateFunction('strright', 'php_right', 2);
+ } else {
+ $error_message = "file not found";
+ $message['message'] = $error_message;
+ $this->message = $message;
+ return false;
+ }
+ }
+
+ if ($this->driver == "mysql") {
+ try {
+ //mysql pdo connection
+ if (strlen($this->host) == 0 && empty($this->port)) {
+ //if both host and port are empty use the unix socket
+ $this->db = new PDO("mysql:host=$this->host;unix_socket=/var/run/mysqld/mysqld.sock;dbname=$this->db_name", $this->username, $this->password);
+ } else {
+ if (empty($this->port)) {
+ //leave out port if it is empty
+ $this->db = new PDO("mysql:host=$this->host;dbname=$this->db_name;", $this->username, $this->password, [
+ PDO::ATTR_ERRMODE,
+ PDO::ERRMODE_EXCEPTION,
+ ]);
+ } else {
+ $this->db = new PDO("mysql:host=$this->host;port=$this->port;dbname=$this->db_name;", $this->username, $this->password, [
+ PDO::ATTR_ERRMODE,
+ PDO::ERRMODE_EXCEPTION,
+ ]);
+ }
+ }
+ } catch (PDOException $e) {
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
+ }
+ }
+
+ if ($this->driver == "pgsql") {
+ //database connection
+ try {
+ if (!empty($this->host)) {
+ if (empty($this->port)) {
+ $this->port = "5432";
+ }
+ if ($this->db_secure === true) {
+ $this->db = new PDO("pgsql:host=$this->host port=$this->port dbname=$this->db_name user=$this->username password=$this->password sslmode=$this->ssl_mode sslrootcert=$this->db_cert_authority");
+ } else {
+ $this->db = new PDO("pgsql:host=$this->host port=$this->port dbname=$this->db_name user=$this->username password=$this->password");
+ }
+ } else {
+ $this->db = new PDO("pgsql:dbname=$this->db_name user=$this->username password=$this->password");
+ }
+ } catch (PDOException $e) {
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
+ }
+ }
+
+ if ($this->driver == "odbc") {
+ //database connection
+ try {
+ $this->db = new PDO("odbc:" . $this->db_name, $this->username, $this->password);
+ } catch (PDOException $e) {
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
+ }
+ }
+
+ //connected to the database
+ return true;
+ }
+
+ /**
+ * Returns the depth of an array
+ *
+ * @param array $array Reference to array
+ *
+ * @return int Depth of array
+ * @internal Moved to class to conserve resources.
+ */
+ public static function array_depth(array &$array) {
+ $depth = 0;
+ if (is_array($array)) {
+ $depth++;
+ foreach ($array as $value) {
+ if (is_array($value)) {
+ $depth = self::array_depth($value) + 1;
+ }
+ }
+ }
+ return $depth;
+ }
+
+ /**
+ * Searches through all fields to see if domain_uuid exists
+ *
+ * @param string $name
+ *
+ * @return boolean true on success and false on failure
+ * @see database::get_apps()
+ * @uses self::$apps directly
+ */
+ public static function domain_uuid_exists($name) {
+ //get the $apps array from the installed apps from the core and mod directories
+ if (count(self::$apps) == 0) {
+ self::get_apps();
+ }
+
+ //search through all fields to see if domain_uuid exists
+ foreach (self::$apps as $x => &$app) {
+ if (is_array($app['db'])) {
+ foreach ($app['db'] as $y => $row) {
+ if (is_array($row['table']['name'])) {
+ $table_name = $row['table']['name']['text'];
+ } else {
+ $table_name = $row['table']['name'];
+ }
+ if ($table_name === self::TABLE_PREFIX . $name) {
+ if (is_array($row['fields'])) {
+ foreach ($row['fields'] as $field) {
+ if ($field['name'] == "domain_uuid") {
+ return true;
+ }
+ } //foreach
+ } //is array
+ }
+ } //foreach
+ } //is array
+ } //foreach
+
+ //not found
+ return false;
+ }
+
+ /**
+ * Returns a new connected database object.
+ *
This allows a shortcut for a common syntax. For more information
+ * on how the connection happens see {@link database::__construct()} and
+ * {@link database::connect()}
+ *
Usage:
+ * $database_object = database::new();
+ *
+ * @return database the new instance of the database object already connected
+ * @see database::__construct()
+ * @see database::connect()
+ */
+ public static function new(array $params = []) {
+
+ //re-use the database connection
+ if (self::$database === null) {
+ self::$database = new database($params);
+ if (!self::$database->is_connected()) {
+ self::$database->connect();
+ }
+ }
+
+ //set the user_uuid
+ if (!empty($params['user_uuid'])) {
+ //use the parameter as the first priority when available
+ self::$database->user_uuid = $params['user_uuid'];
+ } elseif (!empty($_SESSION['user_uuid'])) {
+ //use the session when available
+ self::$database->user_uuid = $_SESSION['user_uuid'];
+ }
+
+ //set the domain_uuid
+ if (!empty($params['domain_uuid'])) {
+ //use the parameter as the first priority when available
+ self::$database->domain_uuid = $params['domain_uuid'];
+ } elseif (!empty($_SESSION['domain_uuid'])) {
+ //use the session when available
+ self::$database->domain_uuid = $_SESSION['domain_uuid'];
+ }
+
+ return self::$database;
+ }
+
+ /**
+ * Ensure the database is still connected and active.
+ *
NOTE:
+ * There is no method in PDO that can reliably detect if the connection is active. Therefore, a lightweight
+ * query is executed using the statement select 1.
+ *
+ * @return bool True if the database is connected. False otherwise.
+ */
+ public function is_connected(): bool {
+ try {
+ $stmt = false;
+ if ($this->db !== null) $stmt = $this->db->query('SELECT 1');
+ return $stmt !== false;
+ } catch (PDOException $ex) {
+ //database is not connected
+ return false;
+ } catch (Exception $e) {
+ //some other error has occurred, so record it
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Magic function called whenever a property is requested.
+ *
If any case statement is removed then access to the variable will be removed.
+ *
+ * @param mixed $name object property
+ *
+ * @return mixed
+ */
+ public function __get($name) {
+ //remove any case statement below to remove access to the variable
+ switch ($name) {
+ case 'name':
+ return $this->app_name;
+ case 'app_name':
+ case 'app_uuid':
+ case 'db':
+ case 'db_cert_authority':
+ case 'db_name':
+ case 'db_secure':
+ case 'domain_uuid':
+ case 'driver':
+ case 'fields':
+ case 'host':
+ case 'limit':
+ case 'message':
+ case 'offset':
+ case 'order_by':
+ case 'order_type':
+ case 'password':
+ case 'path':
+ case 'port':
+ case 'result':
+ case 'sql':
+ case 'table':
+ case 'type':
+ case 'username':
+ case 'where':
+ case 'debug':
+ return $this->{$name};
+ case 'count':
+ return $this->count();
+ default:
+ trigger_error('Object property not available', E_USER_ERROR);
+ }
+ }
+
/**
*
Magic function called whenever a property is attempted to be set.
*
This is used to protect the values stored in the object properties.
- * @param mixed $name Name of object property
+ *
+ * @param mixed $name Name of object property
* @param mixed $value Value of property
*/
- public function __set($name,$value) {
- switch($name) {
+ public function __set($name, $value) {
+ switch ($name) {
case 'name':
case 'app_name':
$this->app_name = self::sanitize($value);
@@ -384,16 +745,22 @@ class database {
break;
case 'port':
$value = (int)$value; // force cast to int
- if ($value > 1023 && $value < 65536) { $this->port = $value; } //valid values are 1024...65535
- else { trigger_error('Port not a valid range', E_USER_ERROR); }
+ if ($value > 1023 && $value < 65536) {
+ $this->port = $value;
+ } //valid values are 1024...65535
+ else {
+ trigger_error('Port not a valid range', E_USER_ERROR);
+ }
break;
case 'app_uuid':
case 'domain_uuid':
- if (is_uuid($value)) { $this->domain_uuid = $value; }
+ if (is_uuid($value)) {
+ $this->domain_uuid = $value;
+ }
break;
case 'type':
case 'driver':
- switch($value) {
+ switch ($value) {
case 'pgsql':
case 'mysql':
case 'sqlite':
@@ -426,324 +793,222 @@ class database {
}
/**
- * Magic function called whenever a property is requested.
- *
If any case statement is removed then access to the variable will be removed.
- * @param mixed $name object property
- * @return mixed
+ * Returns a sanitized string value safe for the database or table name.
+ *
+ * @param string $value To be sanitized
+ *
+ * @return string Sanitized using preg_replace('#[^a-zA-Z0-9_\-]#', '')
+ * @see preg_replace()
*/
- public function __get($name) {
- //remove any case statement below to remove access to the variable
- switch($name) {
- case 'name':
- return $this->app_name;
- case 'app_name':
- case 'app_uuid':
- case 'db':
- case 'db_cert_authority':
- case 'db_name':
- case 'db_secure':
- case 'domain_uuid':
- case 'driver':
- case 'fields':
- case 'host':
- case 'limit':
- case 'message':
- case 'offset':
- case 'order_by':
- case 'order_type':
- case 'password':
- case 'path':
- case 'port':
- case 'result':
- case 'sql':
- case 'table':
- case 'type':
- case 'username':
- case 'where':
- case 'debug':
- case 'count':
- return $this->count();
- default:
- trigger_error('Object property not available', E_USER_ERROR);
+ public static function sanitize(string $value) {
+ return preg_replace('#[^a-zA-Z0-9_\-]#', '', $value);
+ }
+
+/**
+ * Counts the number of rows.
+ *
+ * @return int Represents the number of counted rows or -1 if failed.
+ */
+ public function count() {
+
+ //connect to the database if needed
+ if (!$this->db) {
+ $this->connect();
+ }
+
+ //return if the table name is not set
+ if (empty($this->table)) {
+ return;
+ }
+
+ //sanitize the table name
+ //$this->table = self::sanitize($this->table); // no longer needed
+
+ //get the number of rows
+ $sql = "select count(*) as num_rows from " . $this->table . " ";
+ $i = 0;
+ if (is_array($this->where)) {
+ foreach ($this->where as $row) {
+ //sanitize the name
+ $row['name'] = self::sanitize($row['name']);
+
+ //validate the operator
+ switch ($row['operator']) {
+ case "<":
+ break;
+ case ">":
+ break;
+ case "<=":
+ break;
+ case ">=":
+ break;
+ case "=":
+ break;
+ case "<>":
+ break;
+ case "!=":
+ break;
+ default:
+ //invalid operator
+ return -1;
+ }
+
+ //build the sql
+ if ($i == 0) {
+ $sql .= "where " . $row['name'] . " " . $row['operator'] . " :" . $row['name'] . " ";
+ } else {
+ $sql .= "and " . $row['name'] . " " . $row['operator'] . " :" . $row['name'] . " ";
+ }
+
+ //add the name and value to the params array
+ $params[$row['name']] = $row['value'];
+
+ //increment $i
+ $i++;
+ }
+ }
+
+ //unset($this->where); //should not be objects resposibility
+ $prep_statement = $this->db->prepare($sql);
+ if ($prep_statement) {
+ if (!isset($params)) {
+ $params = null;
+ }
+ $prep_statement->execute($params);
+ $row = $prep_statement->fetch(PDO::FETCH_ASSOC);
+ if ($row['num_rows'] > 0) {
+ return $row['num_rows'];
+ } else {
+ return 0;
+ }
+ }
+ unset($prep_statement);
+
+ }
+
+ public function execute($sql, $parameters = null, $return_type = 'all') {
+
+ //connect to the database if needed
+ if (!$this->db) {
+ $this->connect();
+ }
+
+ //set the error mode
+ $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ //run the query, and return the results
+ try {
+ $prep_statement = $this->db->prepare($sql);
+ if (is_array($parameters)) {
+ $prep_statement->execute($parameters);
+ } else {
+ $prep_statement->execute();
+ }
+ $message["message"] = "OK";
+ $message["code"] = "200";
+ $message["sql"] = $sql;
+ if (is_array($parameters)) {
+ $message["parameters"] = $parameters;
+ }
+ $this->message = $message;
+
+ //return the results
+ switch ($return_type) {
+ case 'all':
+ return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
+ case 'row':
+ return $prep_statement->fetch(PDO::FETCH_ASSOC);
+ case 'column';
+ return $prep_statement->fetchColumn();
+ default:
+ return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
+ }
+ } catch (PDOException $e) {
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
}
}
+ // Use this function to run complex queries
+
/**
* Returns the config object used to create this database object
+ *
* @return config Config object
*/
public function config(): config {
return $this->config;
}
- /**
- *
Connect to the database.
- *
Database driver must be set before calling connect.
- *
For types other than sqlite. Execution will stop on failure.
- * @depends database::driver Alias of database::type.
- *
- */
- public function connect() {
-
- //get the database connection settings
- //$db_type = $conf['database.0.type'];
- //$db_host = $conf['database.0.host'];
- //$db_port = $conf['database.0.port'];
- //$db_name = $conf['database.0.name'];
- //$db_username = $conf['database.0.username'];
- //$db_password = $conf['database.0.password'];
-
- //debug info
- //echo "db type:".$db_type."\n";
- //echo "db host:".$db_host."\n";
- //echo "db port:".$db_port."\n";
- //echo "db name:".$db_name."\n";
- //echo "db username:".$db_username."\n";
- //echo "db password:".$db_password."\n";
- //echo "db path:".$db_path."\n";
- //echo "\n";
-
- //set defaults
- if (!isset($this->driver) && isset($db_type)) { $this->driver = $db_type; }
- if (!isset($this->type) && isset($db_type)) { $this->type = $db_type; }
- if (!isset($this->host) && isset($db_host)) { $this->host = $db_host; }
- if (!isset($this->port) && isset($db_port)) { $this->port = $db_port; }
- if (!isset($this->db_name) && isset($db_name)) { $this->db_name = $db_name; }
- if (!isset($this->db_secure) && isset($db_secure)) {
- $this->db_secure = $db_secure;
- }
- else {
- $this->db_secure = false;
- }
- if (!isset($this->username) && isset($db_username)) { $this->username = $db_username; }
- if (!isset($this->password) && isset($db_password)) { $this->password = $db_password; }
- if (!isset($this->path) && isset($db_path)) { $this->path = $db_path; }
-
- if ($this->driver == "sqlite") {
- if (empty($this->db_name)) {
- $server_name = $_SERVER["SERVER_NAME"];
- $server_name = str_replace ("www.", "", $server_name);
- $db_name_short = $server_name;
- $this->db_name = $server_name.'.db';
- }
- else {
- $db_name_short = $this->db_name;
- }
- $this->path = realpath($this->path);
- if (file_exists($this->path.'/'.$this->db_name)) {
- //connect to the database
- $this->db = new PDO('sqlite:'.$this->path.'/'.$this->db_name); //sqlite 3
- //PRAGMA commands
- $this->db->query('PRAGMA foreign_keys = ON;');
- $this->db->query('PRAGMA journal_mode = wal;');
- //add additional functions to SQLite so that they are accessible inside SQL
- //bool PDO::sqliteCreateFunction ( string function_name, callback callback [, int num_args] )
- $this->db->sqliteCreateFunction('md5', 'php_md5', 1);
- $this->db->sqliteCreateFunction('unix_timestamp', 'php_unix_timestamp', 1);
- $this->db->sqliteCreateFunction('now', 'php_now', 0);
- $this->db->sqliteCreateFunction('sqlitedatatype', 'php_sqlite_data_type', 2);
- $this->db->sqliteCreateFunction('strleft', 'php_left', 2);
- $this->db->sqliteCreateFunction('strright', 'php_right', 2);
- }
- else {
- $error_message = "file not found";
- $message['message'] = $error_message;
- $this->message = $message;
- return false;
- }
- }
-
- if ($this->driver == "mysql") {
- try {
- //mysql pdo connection
- if (strlen($this->host) == 0 && empty($this->port)) {
- //if both host and port are empty use the unix socket
- $this->db = new PDO("mysql:host=$this->host;unix_socket=/var/run/mysqld/mysqld.sock;dbname=$this->db_name", $this->username, $this->password);
- }
- else {
- if (empty($this->port)) {
- //leave out port if it is empty
- $this->db = new PDO("mysql:host=$this->host;dbname=$this->db_name;", $this->username, $this->password, array(
- PDO::ATTR_ERRMODE,
- PDO::ERRMODE_EXCEPTION
- ));
- }
- else {
- $this->db = new PDO("mysql:host=$this->host;port=$this->port;dbname=$this->db_name;", $this->username, $this->password, array(
- PDO::ATTR_ERRMODE,
- PDO::ERRMODE_EXCEPTION
- ));
- }
- }
- }
- catch (PDOException $e) {
- $message['message'] = $e->getMessage();
- $message['code'] = $e->getCode();
- $message['line'] = $e->getLine();
- $message['file'] = $e->getFile();
- $message['trace'] = $e->getTraceAsString();
- $message['debug'] = debug_backtrace();
- $this->message = $message;
- return false;
- }
- }
-
- if ($this->driver == "pgsql") {
- //database connection
- try {
- if (!empty($this->host)) {
- if (empty($this->port)) { $this->port = "5432"; }
- if ($this->db_secure === true) {
- $this->db = new PDO("pgsql:host=$this->host port=$this->port dbname=$this->db_name user=$this->username password=$this->password sslmode=$this->ssl_mode sslrootcert=$this->db_cert_authority");
- }
- else {
- $this->db = new PDO("pgsql:host=$this->host port=$this->port dbname=$this->db_name user=$this->username password=$this->password");
- }
- }
- else {
- $this->db = new PDO("pgsql:dbname=$this->db_name user=$this->username password=$this->password");
- }
- }
- catch (PDOException $e) {
- $message['message'] = $e->getMessage();
- $message['code'] = $e->getCode();
- $message['line'] = $e->getLine();
- $message['file'] = $e->getFile();
- $message['trace'] = $e->getTraceAsString();
- $message['debug'] = debug_backtrace();
- $this->message = $message;
- return false;
- }
- }
-
- if ($this->driver == "odbc") {
- //database connection
- try {
- $this->db = new PDO("odbc:".$this->db_name, $this->username, $this->password);
- }
- catch (PDOException $e) {
- $message['message'] = $e->getMessage();
- $message['code'] = $e->getCode();
- $message['line'] = $e->getLine();
- $message['file'] = $e->getFile();
- $message['trace'] = $e->getTraceAsString();
- $message['debug'] = debug_backtrace();
- $this->message = $message;
- return false;
- }
- }
-
- //connected to the database
- return true;
- }
-
- /**
+ /**
* Returns the table names from the database.
+ *
* @return array tables
* @depends connect()
*/
public function tables() {
- $result = [];
+ $result = [];
//connect to the database if needed
- if (!$this->db) {
- $this->connect();
- }
- if ($this->type == "sqlite") {
- $sql = "SELECT name FROM sqlite_master ";
- $sql .= "WHERE type='table' ";
- $sql .= "order by name;";
- }
- if ($this->type == "pgsql") {
- $sql = "select table_name as name ";
- $sql .= "from information_schema.tables ";
- $sql .= "where table_schema='public' ";
- $sql .= "and table_type='BASE TABLE' ";
- $sql .= "order by table_name ";
- }
- if ($this->type == "mysql") {
- $sql = "show tables";
- }
- if ($this->type == "mssql") {
- $sql = "SELECT * FROM sys.Tables order by name asc";
- }
- $prep_statement = $this->db->prepare($sql);
- $prep_statement->execute();
- $tmp = $prep_statement->fetchAll(PDO::FETCH_NAMED);
- if ($this->type == "pgsql" || $this->type == "sqlite" || $this->type == "mssql") {
- if (is_array($tmp)) {
- foreach ($tmp as $row) {
- $result[]['name'] = $row['name'];
- }
+ if (!$this->db) {
+ $this->connect();
+ }
+ if ($this->type == "sqlite") {
+ $sql = "SELECT name FROM sqlite_master ";
+ $sql .= "WHERE type='table' ";
+ $sql .= "order by name;";
+ }
+ if ($this->type == "pgsql") {
+ $sql = "select table_name as name ";
+ $sql .= "from information_schema.tables ";
+ $sql .= "where table_schema='public' ";
+ $sql .= "and table_type='BASE TABLE' ";
+ $sql .= "order by table_name ";
+ }
+ if ($this->type == "mysql") {
+ $sql = "show tables";
+ }
+ if ($this->type == "mssql") {
+ $sql = "SELECT * FROM sys.Tables order by name asc";
+ }
+ $prep_statement = $this->db->prepare($sql);
+ $prep_statement->execute();
+ $tmp = $prep_statement->fetchAll(PDO::FETCH_NAMED);
+ if ($this->type == "pgsql" || $this->type == "sqlite" || $this->type == "mssql") {
+ if (is_array($tmp)) {
+ foreach ($tmp as $row) {
+ $result[]['name'] = $row['name'];
}
}
- if ($this->type == "mysql") {
- if (is_array($tmp)) {
- foreach ($tmp as $row) {
- $table_array = array_values($row);
- $result[]['name'] = $table_array[0];
- }
+ }
+ if ($this->type == "mysql") {
+ if (is_array($tmp)) {
+ foreach ($tmp as $row) {
+ $table_array = array_values($row);
+ $result[]['name'] = $table_array[0];
}
}
- return $result;
- }
+ }
+ return $result;
+ } //delete
- /**
- * Returns table information from the database.
- * @return array table info
- * @depends connect()
- */
- public function table_info() {
- //public $db;
- //public $type;
- //public $table;
- //public $name;
-
- //connect to the database if needed
- if (!$this->db) {
- $this->connect();
- }
-
- //get the table info
- if (empty($this->table)) { return false; }
- if ($this->type == "sqlite") {
- $sql = "PRAGMA table_info(".$this->table.");";
- }
- if ($this->type == "pgsql") {
- $sql = "SELECT ordinal_position, ";
- $sql .= "column_name, ";
- $sql .= "data_type, ";
- $sql .= "column_default, ";
- $sql .= "is_nullable, ";
- $sql .= "character_maximum_length, ";
- $sql .= "numeric_precision ";
- $sql .= "FROM information_schema.columns ";
- $sql .= "WHERE table_name = '".$this->table."' ";
- $sql .= "and table_catalog = '".$this->db_name."' ";
- $sql .= "ORDER BY ordinal_position; ";
- }
- if ($this->type == "mysql") {
- $sql = "DESCRIBE ".$this->table.";";
- }
- if ($this->type == "mssql") {
- $sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '".$this->table."'";
- }
- $prep_statement = $this->db->prepare($sql);
- $prep_statement->execute();
-
- //set the result array
- return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
- }
-
- /**
+ /**
* Checks if the table exists in the database.
*
Note:
* Table name must be sanitized. Otherwise, a warning will be
* emitted and false will be returned.
+ *
* @param string $table_name Sanitized name of the table to search for.
+ *
* @return boolean Returns true if the table exists and false if it does not.
* @depends connect()
*/
- public function table_exists (string $table_name) {
+ public function table_exists(string $table_name) {
if (self::sanitize($table_name) != $table_name) {
trigger_error('Table Name must be sanitized', E_USER_WARNING);
return false;
@@ -775,30 +1040,31 @@ class database {
$sql .= "select * from pg_tables where schemaname='public' and tablename = '$table_name' ";
}
if ($this->type == "mysql") {
- $sql .= "SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = '".$this->db_name."' and TABLE_NAME = '$table_name' ";
+ $sql .= "SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = '" . $this->db_name . "' and TABLE_NAME = '$table_name' ";
}
$prep_statement = $this->db->prepare($sql);
$prep_statement->execute();
$result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
if (count($result) > 0) {
return true; //table exists
- }
- else {
+ } else {
return false; //table doesn't exist
}
- }
+ } //count
- /**
+ /**
* Checks if the column exists in the database.
*
Note:
* Tables and Column names must be sanitized. Otherwise, a warning will be
* emitted and false will be returned.
- * @param string $table_name Sanitized name of the table to search for.
+ *
+ * @param string $table_name Sanitized name of the table to search for.
* @param string $column_name Sanitized name of the column to search for.
+ *
* @return boolean Returns true if the column exists and false if it does not.
* @depends connect()
*/
- public function column_exists (string $table_name, string $column_name) {
+ public function column_exists(string $table_name, string $column_name) {
//sanitize the table name
if (self::sanitize($table_name) != $table_name) {
trigger_error('Table Name must be sanitized', E_USER_WARNING);
@@ -820,7 +1086,7 @@ class database {
if (!$this->db) {
$backtrace = debug_backtrace();
echo "Connection Failed \n";
- echo "line number ".__line__." \n";
+ echo "line number " . __line__ . " \n";
echo "
";
print_r($backtrace);
echo "
";
@@ -852,8 +1118,7 @@ class database {
//return the results from the sql query
if (empty($sql)) {
return false;
- }
- else {
+ } else {
$prep_statement = $this->db->prepare($sql);
$prep_statement->execute();
$result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
@@ -862,18 +1127,18 @@ class database {
}
if (count($result) > 0) {
return true;
- }
- else {
+ } else {
return false;
}
unset ($prep_statement);
}
- }
+ } //select
/**
* Queries {@link database::table_info()} to return the fields.
- * @access public
+ *
+ * @access public
* @return array Two dimensional array
* @depends table_info()
*/
@@ -884,46 +1149,96 @@ class database {
//public $name;
//initialize the array
- $result = [];
+ $result = [];
//get the table info
- $table_info = $this->table_info();
+ $table_info = $this->table_info();
//set the list of fields
- if ($this->type == "sqlite") {
- if (is_array($table_info)) {
- foreach($table_info as $row) {
- $result[]['name'] = $row['name'];
- }
+ if ($this->type == "sqlite") {
+ if (is_array($table_info)) {
+ foreach ($table_info as $row) {
+ $result[]['name'] = $row['name'];
}
}
- if ($this->type == "pgsql") {
- if (is_array($table_info)) {
- foreach($table_info as $row) {
- $result[]['name'] = $row['column_name'];
- }
+ }
+ if ($this->type == "pgsql") {
+ if (is_array($table_info)) {
+ foreach ($table_info as $row) {
+ $result[]['name'] = $row['column_name'];
}
}
- if ($this->type == "mysql") {
- if (is_array($table_info)) {
- foreach($table_info as $row) {
- $result[]['name'] = $row['Field'];
- }
+ }
+ if ($this->type == "mysql") {
+ if (is_array($table_info)) {
+ foreach ($table_info as $row) {
+ $result[]['name'] = $row['Field'];
}
}
- if ($this->type == "mssql") {
- if (is_array($table_info)) {
- foreach($table_info as $row) {
- $result[]['name'] = $row['COLUMN_NAME'];
- }
+ }
+ if ($this->type == "mssql") {
+ if (is_array($table_info)) {
+ foreach ($table_info as $row) {
+ $result[]['name'] = $row['COLUMN_NAME'];
}
}
+ }
//return the result array
- return $result;
+ return $result;
}
/**
+ * Returns table information from the database.
+ *
+ * @return array table info
+ * @depends connect()
+ */
+ public function table_info() {
+ //public $db;
+ //public $type;
+ //public $table;
+ //public $name;
+
+ //connect to the database if needed
+ if (!$this->db) {
+ $this->connect();
+ }
+
+ //get the table info
+ if (empty($this->table)) {
+ return false;
+ }
+ if ($this->type == "sqlite") {
+ $sql = "PRAGMA table_info(" . $this->table . ");";
+ }
+ if ($this->type == "pgsql") {
+ $sql = "SELECT ordinal_position, ";
+ $sql .= "column_name, ";
+ $sql .= "data_type, ";
+ $sql .= "column_default, ";
+ $sql .= "is_nullable, ";
+ $sql .= "character_maximum_length, ";
+ $sql .= "numeric_precision ";
+ $sql .= "FROM information_schema.columns ";
+ $sql .= "WHERE table_name = '" . $this->table . "' ";
+ $sql .= "and table_catalog = '" . $this->db_name . "' ";
+ $sql .= "ORDER BY ordinal_position; ";
+ }
+ if ($this->type == "mysql") {
+ $sql = "DESCRIBE " . $this->table . ";";
+ }
+ if ($this->type == "mssql") {
+ $sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" . $this->table . "'";
+ }
+ $prep_statement = $this->db->prepare($sql);
+ $prep_statement->execute();
+
+ //set the result array
+ return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ /**
* Searches database using the following object properties:
*
*
table - sanitized name of the table {@see database::table}
@@ -932,6 +1247,7 @@ class database {
*
limit - limit clause {@see database::limit}
*
offset - offset clause {@see database::offset}
*
+ *
* @return boolean
* @depends connect()
*/
@@ -944,565 +1260,47 @@ class database {
//offset;
//connect to the database if needed
- if (!$this->db) {
- $this->connect();
- }
+ if (!$this->db) {
+ $this->connect();
+ }
//get data from the database
- $sql = "select * from ".$this->table." ";
- if ($this->where) {
- $i = 0;
- if (is_array($this->where)) {
- foreach($this->where as $row) {
- //sanitize the name
- $row['name'] = self::sanitize($row['name']);
-
- //validate the operator
- switch ($row['operator']) {
- case "<": break;
- case ">": break;
- case "<=": break;
- case ">=": break;
- case "=": break;
- case "<>": break;
- case "!=": break;
- default:
- //invalid operator
- return false;
- }
-
- //build the sql
- if ($i == 0) {
- //$sql .= 'where '.$row['name']." ".$row['operator']." '".$row['value']."' ";
- $sql .= 'where '.$row['name']." ".$row['operator']." :".$row['name']." ";
- }
- else {
- //$sql .= "and ".$row['name']." ".$row['operator']." '".$row['value']."' ";
- $sql .= "and ".$row['name']." ".$row['operator']." :".$row['name']." ";
- }
-
- //add the name and value to the params array
- $params[$row['name']] = $row['value'];
-
- //increment $i
- $i++;
- }
- }
- }
- if (is_array($this->order_by)) {
- $sql .= "order by ";
- $i = 1;
- if (is_array($this->order_by)) {
- foreach($this->order_by as $row) {
- //sanitize the name
- $row['name'] = self::sanitize($row['name']);
-
- //sanitize the order
- switch ($row['order']) {
- case "asc":
- break;
- case "desc":
- break;
- default:
- $row['order'] = '';
- }
-
- //build the sql
- if (count($this->order_by) == $i) {
- $sql .= $row['name']." ".$row['order']." ";
- }
- else {
- $sql .= $row['name']." ".$row['order'].", ";
- }
-
- //increment $i
- $i++;
- }
- }
- }
-
- //limit
- if (isset($this->limit) && is_numeric($this->limit)) {
- $sql .= "limit ".$this->limit." ";
- }
- //offset
- if (isset($this->offset) && is_numeric($this->offset)) {
- $sql .= "offset ".$this->offset." ";
- }
-
- $prep_statement = $this->db->prepare($sql);
- if ($prep_statement) {
- $prep_statement->execute($params);
- $array = $prep_statement->fetchAll(PDO::FETCH_ASSOC);
- unset($prep_statement);
- return $array;
- }
- else {
- return false;
- }
- }
-
- // Use this function to run complex queries
- public function execute($sql, $parameters = null, $return_type = 'all') {
-
- //connect to the database if needed
- if (!$this->db) {
- $this->connect();
- }
-
- //set the error mode
- $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-
- //run the query, and return the results
- try {
- $prep_statement = $this->db->prepare($sql);
- if (is_array($parameters)) {
- $prep_statement->execute($parameters);
- }
- else {
- $prep_statement->execute();
- }
- $message["message"] = "OK";
- $message["code"] = "200";
- $message["sql"] = $sql;
- if (is_array($parameters)) {
- $message["parameters"] = $parameters;
- }
- $this->message = $message;
-
- //return the results
- switch($return_type) {
- case 'all':
- return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
- case 'row':
- return $prep_statement->fetch(PDO::FETCH_ASSOC);
- case 'column';
- return $prep_statement->fetchColumn();
- default:
- return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
- }
- }
- catch(PDOException $e) {
- $message['message'] = $e->getMessage();
- $message['code'] = $e->getCode();
- $message['line'] = $e->getLine();
- $message['file'] = $e->getFile();
- $message['trace'] = $e->getTraceAsString();
- $message['debug'] = debug_backtrace();
- $this->message = $message;
- return false;
- }
- }
-
- public function delete(array $array) {
- //set the default value
- $retval = true;
-
- //return the array
- if (!is_array($array)) { return false; }
-
- //connect to the database if needed
- if (!$this->db) {
- $this->connect();
- }
-
- //set the message id
- $m = 0;
-
- //debug sql
- //$this->debug["sql"] = true;
-
- //set the message id
- $m = 0;
-
- //loop through the array
- $checked = false;
- $x = 0;
- foreach ($array as $parent_name => $tables) {
- if (is_array($tables)) {
-
- //get the application name and uuid
- if (class_exists($parent_name) && defined("$parent_name::app_name")) {
- $this->app_name = $parent_name::app_name;
- $this->app_uuid = $parent_name::app_uuid;
- }
-
- //process the array
- foreach ($tables as $id => $row) {
-
- //prepare the variables
- $parent_name = self::sanitize($parent_name);
- $parent_key_name = self::singular($parent_name)."_uuid";
-
- //build the delete array
- if (!empty($row['checked']) && $row['checked'] == 'true') {
- //set checked to true
- $checked = true;
-
- //delete the child data
- if (isset($row[$parent_key_name])) {
- $new_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
- }
-
- //remove the row from the main array
- unset($array[$parent_name][$x]);
- }
-
- //loop through the fields
- foreach($row as $field_name => $field_value) {
-
- //find the child tables
- $y = 0;
- if (is_array($field_value)) {
- //prepare the variables
- $child_name = self::sanitize($field_name);
- $child_key_name = self::singular($child_name)."_uuid";
-
- //loop through the child rows
- foreach ($field_value as $sub_row) {
-
- //build the delete array
- if ($row['checked'] == 'true') {
- //set checked to true
- $checked = true;
-
- //delete the child data
- $new_array[$child_name][][$child_key_name] = $sub_row[$child_key_name];
-
- //remove the row from the main array
- unset($array[$parent_name][$x][$child_name][$y]);
- }
-
- //increment the value
- $y++;
- }
- }
- }
-
- //increment the value
- $x++;
-
- }
- }
- }
-
- //if not checked, then copy the array to the delete array
- if (!$checked) {
- $new_array = $array;
- }
-
- //get the current data
- if (count($new_array) > 0) {
- //build an array of tables, fields, and values
- foreach($new_array as $table_name => $rows) {
- foreach($rows as $row) {
- foreach($row as $field_name => $field_value) {
- $keys[$table_name][$field_name][] = $field_value;
- }
- }
- }
-
- //use the array to get a copy of the parent data before deleting it
- foreach($new_array as $table_name => $rows) {
- foreach($rows as $row) {
- $table_name = self::sanitize($table_name);
- $sql = "select * from ".self::TABLE_PREFIX.$table_name." ";
- $i = 0;
- foreach($row as $field_name => $field_value) {
- if ($i == 0) { $sql .= "where "; } else { $sql .= "and "; }
- $sql .= $field_name." in ( ";
- $i = 0;
- foreach($keys[$table_name][$field_name] as $field_value) {
- $field_name = self::sanitize($field_name);
- if ($i > 0) { $sql .= " ,"; }
- $sql .= " :".$field_name."_".$i." ";
- $i++;
- }
- $sql .= ") ";
- $i = 0;
- foreach($keys[$table_name][$field_name] as $field_value) {
- $parameters[$field_name.'_'.$i] = $field_value;
- $i++;
- }
- }
- }
- if (isset($field_value) && $field_value != '') {
- $results = $this->execute($sql, $parameters, 'all');
- unset($parameters);
- if (is_array($results)) {
- $old_array[$table_name] = $results;
- }
- }
- }
-
- //get relations array
- $relations = self::get_relations($parent_name);
-
- //add child data to the old array
- foreach($old_array as $parent_name => $rows) {
- //get relations array
- $relations = self::get_relations($parent_name);
-
- //loop through the rows
- $x = 0;
- foreach($rows as $row) {
- if (is_array($relations)) {
- foreach ($relations as $relation) {
- if ($relation['key']['action']['delete'] == 'cascade') {
- //set the child table
- $child_table = $relation['table'];
-
- //remove the v_ prefix
- if (substr($child_table, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX) {
- $child_table = substr($child_table, strlen(self::TABLE_PREFIX));
- }
-
- //get the child data
- $sql = "select * from ".self::TABLE_PREFIX.$child_table." ";
- $sql .= "where ".$relation['field']." = :".$relation['field'];
- $parameters[$relation['field']] = $row[$relation['field']];
- $results = $this->execute($sql, $parameters, 'all');
- unset($parameters);
- if (is_array($results) && $parent_name !== $child_table) {
- $old_array[$parent_name][$x][$child_table] = $results;
- }
-
- //delete the child data
- if (isset($row[$relation['field']]) && !empty($row[$relation['field']])) {
- $sql = "delete from ".self::TABLE_PREFIX.$child_table." ";
- $sql .= "where ".$relation['field']." = :".$relation['field'];
- $parameters[$relation['field']] = $row[$relation['field']];
-// $this->execute($sql, $parameters);
- }
- unset($parameters);
- }
- }
- }
- $x++;
- }
- }
- }
-
- //use a try catch around the transaction
- try {
-
- //start the atomic transaction
- $this->db->beginTransaction();
-
- //delete the current data
- foreach($new_array as $table_name => $rows) {
- //get the application name and uuid
- if (class_exists($table_name) && defined("$table_name::app_name")) {
- $this->app_name = $table_name::app_name;
- $this->app_uuid = $table_name::app_uuid;
- }
- if (empty($this->app_name)) {
- $app_name_singular = self::singular($table_name);
- if (class_exists($app_name_singular) && defined("$app_name_singular::app_name")) {
- $this->app_name = $app_name_singular::app_name;
- $this->app_uuid = $app_name_singular::app_uuid;
- }
- }
-
- //build and run the delete SQL statements
- foreach($rows as $row) {
- if (permission_exists(self::singular($table_name).'_delete')) {
- $sql = "delete from ".self::TABLE_PREFIX.$table_name." ";
- $i = 0;
- foreach($row as $field_name => $field_value) {
- //echo "field: ".$field_name." = ".$field_value."\n";
- if ($i == 0) { $sql .= "where "; } else { $sql .= "and "; }
- $sql .= $field_name." = :".$field_name." ";
- $parameters[$field_name] = $field_value;
- $i++;
- }
- try {
- $this->execute($sql, $parameters);
- $message["message"] = "OK";
- $message["code"] = "200";
- $message["uuid"] = $id;
- $message["details"][$m]["name"] = $this->app_name;
- $message["details"][$m]["message"] = "OK";
- $message["details"][$m]["code"] = "200";
- //$message["details"][$m]["uuid"] = $parent_key_value;
- $message["details"][$m]["sql"] = $sql;
-
- $this->message = $message;
- $m++;
- unset($sql, $statement);
- }
- catch(PDOException $e) {
- $retval = false;
- $message["message"] = "Bad Request";
- $message["code"] = "400";
- $message["details"][$m]["name"] = $this->app_name;
- $message["details"][$m]["message"] = $e->getMessage();
- $message["details"][$m]["code"] = "400";
- $message["details"][$m]["sql"] = $sql;
-
- $this->message = $message;
- $m++;
- }
- unset($parameters);
- } //if permission
- } //foreach rows
- } //foreach $array
-
- //commit the atomic transaction
- $this->db->commit();
-
- } catch (\PDOException $e) {
- //rollback the transaction on error
- if ($this->db->inTransaction()) {
- $this->db->rollback();
- }
-
- //prepare the message array
- $message['message'] = $e->getMessage();
- $message['code'] = $e->getCode();
- $message['line'] = $e->getLine();
- $message['file'] = $e->getFile();
- $message['trace'] = $e->getTraceAsString();
- $message['debug'] = debug_backtrace();
- $this->message = $message;
- return false;
- }
-
- //set the action if not set
- $transaction_type = 'delete';
-
- //log the transaction results
- if (file_exists($_SERVER["PROJECT_ROOT"]."/app/database_transactions/app_config.php")) {
- $sql = "insert into ".self::TABLE_PREFIX."database_transactions ";
- $sql .= "(";
- $sql .= "database_transaction_uuid, ";
- if (isset($this->domain_uuid) && is_uuid($this->domain_uuid)) {
- $sql .= "domain_uuid, ";
- }
- if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
- $sql .= "user_uuid, ";
- }
- if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
- $sql .= "app_uuid, ";
- }
- if (isset($this->app_name) && !empty($this->app_name)) {
- $sql .= "app_name, ";
- }
- $sql .= "transaction_code, ";
- $sql .= "transaction_address, ";
- $sql .= "transaction_type, ";
- $sql .= "transaction_date, ";
- $sql .= "transaction_old, ";
- $sql .= "transaction_new, ";
- $sql .= "transaction_result ";
- $sql .= ")";
- $sql .= "values ";
- $sql .= "(";
- $sql .= "'".uuid()."', ";
- if (isset($this->domain_uuid) && is_uuid($this->domain_uuid)) {
- $sql .= "'".$this->domain_uuid."', ";
- }
- if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
- $sql .= ":user_uuid, ";
- }
- if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
- $sql .= ":app_uuid, ";
- }
- if (isset($this->app_name) && !empty($this->app_name)) {
- $sql .= ":app_name, ";
- }
- $sql .= "'".$message["code"]."', ";
- $sql .= ":remote_address, ";
- $sql .= "'".$transaction_type."', ";
- $sql .= "now(), ";
- if (is_array($old_array)) {
- $sql .= ":transaction_old, ";
- }
- else {
- $sql .= "null, ";
- }
- if (is_array($new_array)) {
- $sql .= ":transaction_new, ";
- }
- else {
- $sql .= "null, ";
- }
- $sql .= ":transaction_result ";
- $sql .= ")";
- $statement = $this->db->prepare($sql);
- if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
- $statement->bindParam(':user_uuid', $this->user_uuid);
- }
- if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
- $statement->bindParam(':app_uuid', $this->app_uuid);
- }
- if (isset($this->app_name) && !empty($this->app_name)) {
- $statement->bindParam(':app_name', $this->app_name);
- }
- $statement->bindParam(':remote_address', $_SERVER['REMOTE_ADDR']);
- if (is_array($old_array)) {
- $old_json = json_encode($old_array, JSON_PRETTY_PRINT);
- $statement->bindParam(':transaction_old', $old_json);
- }
- if (is_array($new_array)) {
- $new_json = json_encode($new_array, JSON_PRETTY_PRINT);
- $statement->bindParam(':transaction_new', $new_json);
- }
- $result = json_encode($this->message, JSON_PRETTY_PRINT);
- $statement->bindParam(':transaction_result', $result);
- $statement->execute();
- unset($sql);
- }
- return $retval;
- } //delete
-
- /**
- * Counts the number of rows.
- * @return int Represents the number of counted rows or -1 if failed.
- */
- public function count() {
-
- //connect to the database if needed
- if (!$this->db) {
- $this->connect();
- }
-
- //return if the table name is not set
- if (empty($this->table)) {
- return;
- }
-
- //sanitize the table name
- //$this->table = self::sanitize($this->table); // no longer needed
-
- //get the number of rows
- $sql = "select count(*) as num_rows from ".$this->table." ";
+ $sql = "select * from " . $this->table . " ";
+ if ($this->where) {
$i = 0;
if (is_array($this->where)) {
- foreach($this->where as $row) {
+ foreach ($this->where as $row) {
//sanitize the name
$row['name'] = self::sanitize($row['name']);
//validate the operator
switch ($row['operator']) {
- case "<": break;
- case ">": break;
- case "<=": break;
- case ">=": break;
- case "=": break;
- case "<>": break;
- case "!=": break;
+ case "<":
+ break;
+ case ">":
+ break;
+ case "<=":
+ break;
+ case ">=":
+ break;
+ case "=":
+ break;
+ case "<>":
+ break;
+ case "!=":
+ break;
default:
//invalid operator
- return -1;
+ return false;
}
//build the sql
if ($i == 0) {
- $sql .= "where ".$row['name']." ".$row['operator']." :".$row['name']." ";
- }
- else {
- $sql .= "and ".$row['name']." ".$row['operator']." :".$row['name']." ";
+ //$sql .= 'where '.$row['name']." ".$row['operator']." '".$row['value']."' ";
+ $sql .= 'where ' . $row['name'] . " " . $row['operator'] . " :" . $row['name'] . " ";
+ } else {
+ //$sql .= "and ".$row['name']." ".$row['operator']." '".$row['value']."' ";
+ $sql .= "and " . $row['name'] . " " . $row['operator'] . " :" . $row['name'] . " ";
}
//add the name and value to the params array
@@ -1512,76 +1310,597 @@ class database {
$i++;
}
}
+ }
+ if (is_array($this->order_by)) {
+ $sql .= "order by ";
+ $i = 1;
+ if (is_array($this->order_by)) {
+ foreach ($this->order_by as $row) {
+ //sanitize the name
+ $row['name'] = self::sanitize($row['name']);
- //unset($this->where); //should not be objects resposibility
- $prep_statement = $this->db->prepare($sql);
- if ($prep_statement) {
- if (!isset($params)) { $params = null; }
- $prep_statement->execute($params);
- $row = $prep_statement->fetch(PDO::FETCH_ASSOC);
- if ($row['num_rows'] > 0) {
- return $row['num_rows'];
- }
- else {
- return 0;
+ //sanitize the order
+ switch ($row['order']) {
+ case "asc":
+ break;
+ case "desc":
+ break;
+ default:
+ $row['order'] = '';
+ }
+
+ //build the sql
+ if (count($this->order_by) == $i) {
+ $sql .= $row['name'] . " " . $row['order'] . " ";
+ } else {
+ $sql .= $row['name'] . " " . $row['order'] . ", ";
+ }
+
+ //increment $i
+ $i++;
}
}
+ }
+
+ //limit
+ if (isset($this->limit) && is_numeric($this->limit)) {
+ $sql .= "limit " . $this->limit . " ";
+ }
+ //offset
+ if (isset($this->offset) && is_numeric($this->offset)) {
+ $sql .= "offset " . $this->offset . " ";
+ }
+
+ $prep_statement = $this->db->prepare($sql);
+ if ($prep_statement) {
+ $prep_statement->execute($params);
+ $array = $prep_statement->fetchAll(PDO::FETCH_ASSOC);
unset($prep_statement);
+ return $array;
+ } else {
+ return false;
+ }
+ } //end function copy
- } //count
+ public function delete(array $array) {
+ //set the default value
+ $retval = true;
- /**
- * Performs a select query on database using the $sql statement supplied.
- * @param string $sql Valid SQL statement.
- * @param array|null $parameters Value can be array, empty string, or null.
- * @param string $return_type Values can be set to all, row, or column.
- * @return mixed Returned values can be array, string, boolean, int, or false. This is dependent on $return_type.
- */
+ //return the array
+ if (!is_array($array)) {
+ return false;
+ }
+
+ //connect to the database if needed
+ if (!$this->db) {
+ $this->connect();
+ }
+
+ //set the message id
+ $m = 0;
+
+ //debug sql
+ //$this->debug["sql"] = true;
+
+ //set the message id
+ $m = 0;
+
+ //loop through the array
+ $checked = false;
+ $x = 0;
+ foreach ($array as $parent_name => $tables) {
+ if (is_array($tables)) {
+
+ //get the application name and uuid
+ if (class_exists($parent_name) && defined("$parent_name::app_name")) {
+ $this->app_name = $parent_name::app_name;
+ $this->app_uuid = $parent_name::app_uuid;
+ }
+
+ //process the array
+ foreach ($tables as $id => $row) {
+
+ //prepare the variables
+ $parent_name = self::sanitize($parent_name);
+ $parent_key_name = self::singular($parent_name) . "_uuid";
+
+ //build the delete array
+ if (!empty($row['checked']) && $row['checked'] == 'true') {
+ //set checked to true
+ $checked = true;
+
+ //delete the child data
+ if (isset($row[$parent_key_name])) {
+ $new_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
+ }
+
+ //remove the row from the main array
+ unset($array[$parent_name][$x]);
+ }
+
+ //loop through the fields
+ foreach ($row as $field_name => $field_value) {
+
+ //find the child tables
+ $y = 0;
+ if (is_array($field_value)) {
+ //prepare the variables
+ $child_name = self::sanitize($field_name);
+ $child_key_name = self::singular($child_name) . "_uuid";
+
+ //loop through the child rows
+ foreach ($field_value as $sub_row) {
+
+ //build the delete array
+ if ($row['checked'] == 'true') {
+ //set checked to true
+ $checked = true;
+
+ //delete the child data
+ $new_array[$child_name][][$child_key_name] = $sub_row[$child_key_name];
+
+ //remove the row from the main array
+ unset($array[$parent_name][$x][$child_name][$y]);
+ }
+
+ //increment the value
+ $y++;
+ }
+ }
+ }
+
+ //increment the value
+ $x++;
+
+ }
+ }
+ }
+
+ //if not checked, then copy the array to the delete array
+ if (!$checked) {
+ $new_array = $array;
+ }
+
+ //get the current data
+ if (count($new_array) > 0) {
+ //build an array of tables, fields, and values
+ foreach ($new_array as $table_name => $rows) {
+ foreach ($rows as $row) {
+ foreach ($row as $field_name => $field_value) {
+ $keys[$table_name][$field_name][] = $field_value;
+ }
+ }
+ }
+
+ //use the array to get a copy of the parent data before deleting it
+ foreach ($new_array as $table_name => $rows) {
+ foreach ($rows as $row) {
+ $table_name = self::sanitize($table_name);
+ $sql = "select * from " . self::TABLE_PREFIX . $table_name . " ";
+ $i = 0;
+ foreach ($row as $field_name => $field_value) {
+ if ($i == 0) {
+ $sql .= "where ";
+ } else {
+ $sql .= "and ";
+ }
+ $sql .= $field_name . " in ( ";
+ $i = 0;
+ foreach ($keys[$table_name][$field_name] as $field_value) {
+ $field_name = self::sanitize($field_name);
+ if ($i > 0) {
+ $sql .= " ,";
+ }
+ $sql .= " :" . $field_name . "_" . $i . " ";
+ $i++;
+ }
+ $sql .= ") ";
+ $i = 0;
+ foreach ($keys[$table_name][$field_name] as $field_value) {
+ $parameters[$field_name . '_' . $i] = $field_value;
+ $i++;
+ }
+ }
+ }
+ if (isset($field_value) && $field_value != '') {
+ $results = $this->execute($sql, $parameters, 'all');
+ unset($parameters);
+ if (is_array($results)) {
+ $old_array[$table_name] = $results;
+ }
+ }
+ }
+
+ //get relations array
+ $relations = self::get_relations($parent_name);
+
+ //add child data to the old array
+ foreach ($old_array as $parent_name => $rows) {
+ //get relations array
+ $relations = self::get_relations($parent_name);
+
+ //loop through the rows
+ $x = 0;
+ foreach ($rows as $row) {
+ if (is_array($relations)) {
+ foreach ($relations as $relation) {
+ if ($relation['key']['action']['delete'] == 'cascade') {
+ //set the child table
+ $child_table = $relation['table'];
+
+ //remove the v_ prefix
+ if (substr($child_table, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX) {
+ $child_table = substr($child_table, strlen(self::TABLE_PREFIX));
+ }
+
+ //get the child data
+ $sql = "select * from " . self::TABLE_PREFIX . $child_table . " ";
+ $sql .= "where " . $relation['field'] . " = :" . $relation['field'];
+ $parameters[$relation['field']] = $row[$relation['field']];
+ $results = $this->execute($sql, $parameters, 'all');
+ unset($parameters);
+ if (is_array($results) && $parent_name !== $child_table) {
+ $old_array[$parent_name][$x][$child_table] = $results;
+ }
+
+ //delete the child data
+ if (isset($row[$relation['field']]) && !empty($row[$relation['field']])) {
+ $sql = "delete from " . self::TABLE_PREFIX . $child_table . " ";
+ $sql .= "where " . $relation['field'] . " = :" . $relation['field'];
+ $parameters[$relation['field']] = $row[$relation['field']];
+// $this->execute($sql, $parameters);
+ }
+ unset($parameters);
+ }
+ }
+ }
+ $x++;
+ }
+ }
+ }
+
+ //use a try catch around the transaction
+ try {
+
+ //start the atomic transaction
+ $this->db->beginTransaction();
+
+ //delete the current data
+ foreach ($new_array as $table_name => $rows) {
+ //get the application name and uuid
+ if (class_exists($table_name) && defined("$table_name::app_name")) {
+ $this->app_name = $table_name::app_name;
+ $this->app_uuid = $table_name::app_uuid;
+ }
+ if (empty($this->app_name)) {
+ $app_name_singular = self::singular($table_name);
+ if (class_exists($app_name_singular) && defined("$app_name_singular::app_name")) {
+ $this->app_name = $app_name_singular::app_name;
+ $this->app_uuid = $app_name_singular::app_uuid;
+ }
+ }
+
+ //build and run the delete SQL statements
+ foreach ($rows as $row) {
+ if (permission_exists(self::singular($table_name) . '_delete')) {
+ $sql = "delete from " . self::TABLE_PREFIX . $table_name . " ";
+ $i = 0;
+ foreach ($row as $field_name => $field_value) {
+ //echo "field: ".$field_name." = ".$field_value."\n";
+ if ($i == 0) {
+ $sql .= "where ";
+ } else {
+ $sql .= "and ";
+ }
+ $sql .= $field_name . " = :" . $field_name . " ";
+ $parameters[$field_name] = $field_value;
+ $i++;
+ }
+ try {
+ $this->execute($sql, $parameters);
+ $message["message"] = "OK";
+ $message["code"] = "200";
+ $message["uuid"] = $id;
+ $message["details"][$m]["name"] = $this->app_name;
+ $message["details"][$m]["message"] = "OK";
+ $message["details"][$m]["code"] = "200";
+ //$message["details"][$m]["uuid"] = $parent_key_value;
+ $message["details"][$m]["sql"] = $sql;
+
+ $this->message = $message;
+ $m++;
+ unset($sql, $statement);
+ } catch (PDOException $e) {
+ $retval = false;
+ $message["message"] = "Bad Request";
+ $message["code"] = "400";
+ $message["details"][$m]["name"] = $this->app_name;
+ $message["details"][$m]["message"] = $e->getMessage();
+ $message["details"][$m]["code"] = "400";
+ $message["details"][$m]["sql"] = $sql;
+
+ $this->message = $message;
+ $m++;
+ }
+ unset($parameters);
+ } //if permission
+ } //foreach rows
+ } //foreach $array
+
+ //commit the atomic transaction
+ $this->db->commit();
+
+ } catch (PDOException $e) {
+ //rollback the transaction on error
+ if ($this->db->inTransaction()) {
+ $this->db->rollback();
+ }
+
+ //prepare the message array
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
+ }
+
+ //set the action if not set
+ $transaction_type = 'delete';
+
+ //log the transaction results
+ if (file_exists($_SERVER["PROJECT_ROOT"] . "/app/database_transactions/app_config.php")) {
+ $sql = "insert into " . self::TABLE_PREFIX . "database_transactions ";
+ $sql .= "(";
+ $sql .= "database_transaction_uuid, ";
+ if (isset($this->domain_uuid) && is_uuid($this->domain_uuid)) {
+ $sql .= "domain_uuid, ";
+ }
+ if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
+ $sql .= "user_uuid, ";
+ }
+ if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
+ $sql .= "app_uuid, ";
+ }
+ if (isset($this->app_name) && !empty($this->app_name)) {
+ $sql .= "app_name, ";
+ }
+ $sql .= "transaction_code, ";
+ $sql .= "transaction_address, ";
+ $sql .= "transaction_type, ";
+ $sql .= "transaction_date, ";
+ $sql .= "transaction_old, ";
+ $sql .= "transaction_new, ";
+ $sql .= "transaction_result ";
+ $sql .= ")";
+ $sql .= "values ";
+ $sql .= "(";
+ $sql .= "'" . uuid() . "', ";
+ if (isset($this->domain_uuid) && is_uuid($this->domain_uuid)) {
+ $sql .= "'" . $this->domain_uuid . "', ";
+ }
+ if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
+ $sql .= ":user_uuid, ";
+ }
+ if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
+ $sql .= ":app_uuid, ";
+ }
+ if (isset($this->app_name) && !empty($this->app_name)) {
+ $sql .= ":app_name, ";
+ }
+ $sql .= "'" . $message["code"] . "', ";
+ $sql .= ":remote_address, ";
+ $sql .= "'" . $transaction_type . "', ";
+ $sql .= "now(), ";
+ if (is_array($old_array)) {
+ $sql .= ":transaction_old, ";
+ } else {
+ $sql .= "null, ";
+ }
+ if (is_array($new_array)) {
+ $sql .= ":transaction_new, ";
+ } else {
+ $sql .= "null, ";
+ }
+ $sql .= ":transaction_result ";
+ $sql .= ")";
+ $statement = $this->db->prepare($sql);
+ if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
+ $statement->bindParam(':user_uuid', $this->user_uuid);
+ }
+ if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
+ $statement->bindParam(':app_uuid', $this->app_uuid);
+ }
+ if (isset($this->app_name) && !empty($this->app_name)) {
+ $statement->bindParam(':app_name', $this->app_name);
+ }
+ $statement->bindParam(':remote_address', $_SERVER['REMOTE_ADDR']);
+ if (is_array($old_array)) {
+ $old_json = json_encode($old_array, JSON_PRETTY_PRINT);
+ $statement->bindParam(':transaction_old', $old_json);
+ }
+ if (is_array($new_array)) {
+ $new_json = json_encode($new_array, JSON_PRETTY_PRINT);
+ $statement->bindParam(':transaction_new', $new_json);
+ }
+ $result = json_encode($this->message, JSON_PRETTY_PRINT);
+ $statement->bindParam(':transaction_result', $result);
+ $statement->execute();
+ unset($sql);
+ }
+ return $retval;
+ } //end function toggle
+
+ /**
+ * Converts a plural English word to singular.
+ *
+ * @param string $word English word
+ *
+ * @return string Singular version of English word
+ * @internal Moved to class to conserve resources.
+ */
+ public static function singular(string $word) {
+ //"-es" is used for words that end in "-x", "-s", "-z", "-sh", "-ch" in which case you add
+ if (substr($word, -2) == "es") {
+ if (substr($word, -4) == "sses") { // eg. 'addresses' to 'address'
+ return substr($word, 0, -2);
+ } elseif (substr($word, -3) == "ses") { // eg. 'databases' to 'database' (necessary!)
+ return substr($word, 0, -1);
+ } elseif (substr($word, -3) == "ies") { // eg. 'countries' to 'country'
+ return substr($word, 0, -3) . "y";
+ } elseif (substr($word, -3, 1) == "x") {
+ return substr($word, 0, -2);
+ } elseif (substr($word, -3, 1) == "s") {
+ return substr($word, 0, -2);
+ } elseif (substr($word, -3, 1) == "z") {
+ return substr($word, 0, -2);
+ } elseif (substr($word, -4, 2) == "sh") {
+ return substr($word, 0, -2);
+ } elseif (substr($word, -4, 2) == "ch") {
+ return substr($word, 0, -2);
+ } else {
+ return rtrim($word, "s");
+ }
+ } else {
+ return rtrim($word, "s");
+ }
+ } //save method
+
+ /**
+ * Get Relations searches through all fields to find relations
+ *
+ * @param string $schema Table name
+ *
+ * @return array Returns array or false
+ * @internal Moved to class to conserve resources.
+ */
+ public static function get_relations($schema) {
+
+ //remove the v_ prefix
+ if (substr($schema, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX) {
+ $schema = substr($schema, strlen(self::TABLE_PREFIX));
+ }
+
+ //sanitize the values
+ $schema = self::sanitize($schema);
+
+ //get the apps array
+ $config_list = [];
+ $directories = ["core", "app"];
+ $applications = [$schema, self::singular($schema)];
+ foreach ($directories as $directory) {
+ foreach ($applications as $application) {
+ $path = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/$directory/$application/app_config.php";
+ $app_config_files = glob($path);
+ if ($app_config_files !== false) {
+ $config_list = array_merge($config_list, $app_config_files);
+ }
+ }
+ }
+ $x = 0;
+ foreach ($config_list as $config_path) {
+ include($config_path);
+ $x++;
+ }
+
+ //search through all fields to find relations
+ if (!empty($apps) && is_array($apps)) {
+ foreach ($apps as $x => $app) {
+ foreach ($app['db'] as $y => $row) {
+ foreach ($row['fields'] as $z => $field) {
+ if (!empty($field['deprecated']) && $field['deprecated'] != "true") {
+ if (!empty($field['key']['type']) && $field['key']['type'] == "foreign") {
+ if ($row['table']['name'] == self::TABLE_PREFIX . $schema || $field['key']['reference']['table'] == self::TABLE_PREFIX . $schema) {
+ //get the field name
+ if (!empty($field['name']) && is_array($field['name'])) {
+ $field_name = trim($field['name']['text']);
+ } else {
+ $field_name = trim($field['name']);
+ }
+ //build the array
+ $relations[$i]['table'] = $row['table']['name'];
+ $relations[$i]['field'] = $field_name;
+ $relations[$i]['key']['type'] = $field['key']['type'];
+ $relations[$i]['key']['table'] = $field['key']['reference']['table'];
+ $relations[$i]['key']['field'] = $field['key']['reference']['field'];
+ if (isset($field['key']['reference']['action'])) {
+ $relations[$i]['key']['action'] = $field['key']['reference']['action'];
+ }
+ //increment the value
+ $i++;
+ }
+ }
+ }
+ unset($field_name);
+ }
+ }
+ }
+ }
+
+ //return the array
+ if (!empty($relations) && is_array($relations)) {
+ return $relations;
+ } else {
+ return false;
+ }
+ }
+
+/**
+ * Performs a select query on database using the $sql statement supplied.
+ *
+ * @param string $sql Valid SQL statement.
+ * @param array|null $parameters Value can be array, empty string, or null.
+ * @param string $return_type Values can be set to all, row, or column.
+ *
+ * @return mixed Returned values can be array, string, boolean, int, or false. This is dependent on
+ * $return_type.
+ */
public function select(string $sql, ?array $parameters = [], string $return_type = 'all') {
//connect to the database if needed
- if (!$this->db) {
- $this->connect();
- }
+ if (!$this->db) {
+ $this->connect();
+ }
//unable to connect to the database
- if (!$this->db) {
- $error_message = "Connection Failed \n";
- $error_message .= "line number ".__line__." \n";
- $message['message'] = $error_message;
- $this->message = $message;
- return false;
- }
+ if (!$this->db) {
+ $error_message = "Connection Failed \n";
+ $error_message .= "line number " . __line__ . " \n";
+ $message['message'] = $error_message;
+ $this->message = $message;
+ return false;
+ }
//set the error mode
- if ($this->db) {
- $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
- }
+ if ($this->db) {
+ $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ }
//reduce prepared statement latency
- if ($this->db && defined('PDO::PGSQL_ATTR_DISABLE_PREPARES')) {
- $this->db->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true);
- }
+ if ($this->db && defined('PDO::PGSQL_ATTR_DISABLE_PREPARES')) {
+ $this->db->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true);
+ }
//execute the query and return the results
- try {
- $prep_statement = $this->db->prepare($sql);
- if (is_array($parameters)) {
- $prep_statement->execute($parameters);
- }
- else {
- $prep_statement->execute();
- }
- $message["message"] = "OK";
- $message["code"] = "200";
- $message["sql"] = $sql;
- if (is_array($parameters)) {
- $message["parameters"] = $parameters;
- }
- $this->message = $message;
+ try {
+ $prep_statement = $this->db->prepare($sql);
+ if (is_array($parameters)) {
+ $prep_statement->execute($parameters);
+ } else {
+ $prep_statement->execute();
+ }
+ $message["message"] = "OK";
+ $message["code"] = "200";
+ $message["sql"] = $sql;
+ if (is_array($parameters)) {
+ $message["parameters"] = $parameters;
+ }
+ $this->message = $message;
- //return the results
- switch($return_type) {
+ //return the results
+ switch ($return_type) {
case 'all':
return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
case 'row':
@@ -1590,23 +1909,24 @@ class database {
return $prep_statement->fetchColumn();
default:
return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
- }
}
- catch(PDOException $e) {
- $message['message'] = $e->getMessage();
- $message['code'] = $e->getCode();
- $message['line'] = $e->getLine();
- $message['file'] = $e->getFile();
- $message['trace'] = $e->getTraceAsString();
- $message['debug'] = debug_backtrace();
- $this->message = $message;
- return false;
- }
- } //select
+ } catch (PDOException $e) {
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
+ }
+ }
- /**
+ /**
* Sets the object $result to sql array
+ *
* @param array $array Array containing the table name, uuid, SQL and where clause.
+ *
* @return database Returns the database object or null.
*/
public function find_new(array $array) {
@@ -1630,7 +1950,7 @@ class database {
}
//build the query
- $sql = "SELECT * FROM ".self::TABLE_PREFIX . $this->name . " ";
+ $sql = "SELECT * FROM " . self::TABLE_PREFIX . $this->name . " ";
if (isset($this->uuid)) {
//get the specific uuid
$sql .= "WHERE " . self::singular($this->name) . "_uuid = '" . $this->uuid . "' ";
@@ -1642,13 +1962,20 @@ class database {
if (isset($row['operator'])) {
//validate the operator
switch ($row['operator']) {
- case "<": break;
- case ">": break;
- case "<=": break;
- case ">=": break;
- case "=": break;
- case "<>": break;
- case "!=": break;
+ case "<":
+ break;
+ case ">":
+ break;
+ case "<=":
+ break;
+ case ">=":
+ break;
+ case "=":
+ break;
+ case "<>":
+ break;
+ case "!=":
+ break;
default:
//invalid operator
return null;
@@ -1714,7 +2041,9 @@ class database {
/**
* Stores the passed UUID in the object
+ *
* @param string $uuid A valid UUID must be passed
+ *
* @return database Returns this object
*/
public function uuid(string $uuid) {
@@ -1722,513 +2051,1042 @@ class database {
return $this;
}
- /**
+/**
* Copies records and appends suffix to the column description data
- * @param array $array Three dimensional Array. The first dimension is the table name without the prefix 'v_'. Second dimension in the row value as int. Third dimension is the column name.
+ *
+ * @param array $array Three dimensional Array. The first dimension is the table name without the prefix 'v_'.
+ * Second dimension in the row value as int. Third dimension is the column name.
+ *
* @return bool Returns true on success and false on failure.
*/
public function copy(array $array, $suffix = '(Copy)') {
//set default return value
- $retval = false;
+ $retval = false;
//return the array
- if (!is_array($array)) { return $retval; }
+ if (!is_array($array)) {
+ return $retval;
+ }
//initialize array
- $copy_array = [];
+ $copy_array = [];
//set the message id
- $m = 0;
+ $m = 0;
//loop through the array
- $x = 0;
- foreach ($array as $parent_name => $tables) {
- if (is_array($tables)) {
- foreach ($tables as $id => $row) {
+ $x = 0;
+ foreach ($array as $parent_name => $tables) {
+ if (is_array($tables)) {
+ foreach ($tables as $id => $row) {
- //prepare the variables
- $parent_name = self::sanitize($parent_name);
- $parent_key_name = self::singular($parent_name)."_uuid";
+ //prepare the variables
+ $parent_name = self::sanitize($parent_name);
+ $parent_key_name = self::singular($parent_name) . "_uuid";
- //build the copy array
- if (!empty($row['checked']) && $row['checked'] == 'true') {
- //set checked to true
- $checked = true;
+ //build the copy array
+ if (!empty($row['checked']) && $row['checked'] == 'true') {
+ //set checked to true
+ $checked = true;
- //copy the child data
- if (!empty($row[$parent_key_name]) && is_uuid($row[$parent_key_name])) {
- $copy_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
- }
-
- //remove the row from the main array
- unset($array[$parent_name][$x]);
-
- //loop through the fields
- foreach($row as $field_name => $field_value) {
- //find the child tables
- if (is_array($field_value)) {
-
- //prepare the variables
- $child_name = self::sanitize($field_name);
- $child_key_name = self::singular($child_name)."_uuid";
-
- //loop through the child rows
- $y = 0;
- foreach ($field_value as $sub_row) {
-
- //delete the child data
- $copy_array[$child_name][][$child_key_name] = $sub_row[$child_key_name];
-
- //remove the row from the main array
- unset($array[$parent_name][$x][$child_name][$y]);
-
- //increment the value
- $y++;
- }
- }
- }
- }
-
- //increment the value
- $x++;
-
- }
- }
- }
-
- //get the current data
- if (count($copy_array) > 0) {
-
- //build an array of tables, fields, and values
- foreach($copy_array as $table_name => $rows) {
- foreach($rows as $row) {
- foreach($row as $field_name => $field_value) {
- $keys[$table_name][$field_name][] = $field_value;
+ //copy the child data
+ if (!empty($row[$parent_key_name]) && is_uuid($row[$parent_key_name])) {
+ $copy_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
}
- }
- }
- //unset the array
- unset($array);
-
- //use the array to get a copy of the paent data before deleting it
- foreach($copy_array as $table_name => $rows) {
- foreach($rows as $row) {
- $table_name = self::sanitize($table_name);
- $sql = "select * from ".self::TABLE_PREFIX.$table_name." ";
- $i = 0;
- foreach($row as $field_name => $field_value) {
- if ($i == 0) { $sql .= "where "; } else { $sql .= "and "; }
- $sql .= $field_name." in ( ";
- $i = 0;
- foreach($keys[$table_name][$field_name] as $field_value) {
- $field_name = self::sanitize($field_name);
- if ($i > 0) { $sql .= " ,"; }
- $sql .= " :".$field_name."_".$i." ";
- $i++;
- }
- $sql .= ") ";
- $i = 0;
- foreach($keys[$table_name][$field_name] as $field_value) {
- $parameters[$field_name.'_'.$i] = $field_value;
- $i++;
- }
- }
- }
-
- $results = $this->execute($sql, $parameters, 'all');
- unset($parameters);
- if (is_array($results)) {
- $array[$table_name] = $results;
- }
- }
-
- //add child data to the old array
- foreach($copy_array as $parent_name => $rows) {
- //get relations array
- $relations = self::get_relations($parent_name);
-
- //loop through the rows
- $x = 0;
- foreach($rows as $row) {
- if (is_array($relations)) {
- foreach ($relations as $relation) {
- //set the child table
- $child_table = $relation['table'];
-
- //remove the v_ prefix
- if (substr($child_table, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX) {
- $child_table = substr($child_table, strlen(self::TABLE_PREFIX));
- }
-
- //get the child data
- $sql = "select * from ".self::TABLE_PREFIX.$child_table." ";
- $sql .= "where ".$relation['field']." = :".$relation['field'];
- $parameters[$relation['field']] = $row[$relation['field']];
- $results = $this->execute($sql, $parameters, 'all');
- unset($parameters);
- if (is_array($results)) {
- $array[$parent_name][$x][$child_table] = $results;
- }
- }
- }
- $x++;
- }
- }
- }
-
- //update the parent and child keys
- $checked = false;
- $x = 0;
- foreach ($array as $parent_name => $tables) {
- if (is_array($tables)) {
- foreach ($tables as $id => $row) {
-
- //prepare the variables
- $parent_name = self::sanitize($parent_name);
- $parent_key_name = self::singular($parent_name)."_uuid";
- $parent_key_value = uuid();
-
- //update the parent key id
- $array[$parent_name][$x][$parent_key_name] = $parent_key_value;
-
- //set enabled
- if (array_key_exists(self::singular($parent_name).'_enabled', $array[$parent_name][$x])) {
- $array[$parent_name][$x][self::singular($parent_name).'_enabled'] = $row[self::singular($parent_name).'_enabled'] === true || $row[self::singular($parent_name).'_enabled'] == 'true' ? 'true' : 'false';
- }
- else if (array_key_exists('enabled', $array[$parent_name][$x])) {
- $array[$parent_name][$x]['enabled'] = $row['enabled'] === true || $row['enabled'] == 'true' ? 'true' : 'false';
- }
-
- //add copy to the description
- if (array_key_exists(self::singular($parent_name).'_description', $array[$parent_name][$x])) {
- $array[$parent_name][$x][self::singular($parent_name).'_description'] = trim($array[$parent_name][$x][self::singular($parent_name).'_description'].' '.$suffix);
- }
- else if (array_key_exists('description', $array[$parent_name][$x])) {
- $array[$parent_name][$x]['description'] = trim($array[$parent_name][$x]['description'].' '.$suffix);
- }
+ //remove the row from the main array
+ unset($array[$parent_name][$x]);
//loop through the fields
- foreach($row as $field_name => $field_value) {
+ foreach ($row as $field_name => $field_value) {
+ //find the child tables
+ if (is_array($field_value)) {
- //find the child tables
+ //prepare the variables
+ $child_name = self::sanitize($field_name);
+ $child_key_name = self::singular($child_name) . "_uuid";
+
+ //loop through the child rows
$y = 0;
- if (is_array($field_value)) {
- //prepare the variables
- $child_name = self::sanitize($field_name);
- $child_key_name = self::singular($child_name)."_uuid";
+ foreach ($field_value as $sub_row) {
- //loop through the child rows
- foreach ($field_value as $sub_row) {
- //update the parent key id
- $array[$parent_name][$x][$child_name][$y][$parent_key_name] = $parent_key_value;
-
- //udpate the child key id
- $array[$parent_name][$x][$child_name][$y][$child_key_name] = uuid();
-
- //increment the value
- $y++;
- }
- }
- }
-
- //increment the value
- $x++;
-
- }
- }
- }
-
- //save the copy of the data
- if (is_array($array) && count($array) > 0) {
- $retval = $this->save($array);
- unset($array);
- }
- return $retval;
- } //end function copy
-
- /**
- * Toggles fields on a table using the toggle_field array values within the app object.
- * @param array $array Three dimensional Array. The first dimension is the table name without the prefix 'v_'. Second dimension in the row value as int. Third dimension is the column name.
- * @return bool Returns true on success and false on failure.
- * @depends database::save()
- * @depends database::get_apps()
- */
- public function toggle(array $array) {
-
- //return the array
- if (!is_array($array)) { return false; }
-
- //set the message id
- $m = 0;
-
- //loop through the array
- if (!empty($array) && is_array($array)) {
- $x = 0;
- foreach ($array as $parent_name => $tables) {
- if (!empty($tables) && is_array($tables)) {
- foreach ($tables as $id => $row) {
-
- //prepare the variables
- $parent_name = self::sanitize($parent_name);
- $parent_key_name = self::singular($parent_name)."_uuid";
-
- //build the toggle array
- if (!empty($row['checked']) && $row['checked'] == 'true') {
- //toggle the field value
- //$toggle_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
- $toggle_array[$parent_name][$x] = $row;
+ //delete the child data
+ $copy_array[$child_name][][$child_key_name] = $sub_row[$child_key_name];
//remove the row from the main array
- unset($array[$parent_name][$x]);
- }
+ unset($array[$parent_name][$x][$child_name][$y]);
- //loop through the fields
- foreach($row as $field_name => $field_value) {
-
- //find the child tables
- $y = 0;
- if (!empty($field_value) && is_array($field_value)) {
- //prepare the variables
- $child_name = self::sanitize($field_name);
- $child_key_name = self::singular($child_name)."_uuid";
-
- //loop through the child rows
- foreach ($field_value as $sub_row) {
-
- //build the delete array
- if ($sub_row['checked'] == 'true') {
- //delete the child data
- $delete_array[$child_name][$y][$child_key_name] = $sub_row[$child_key_name];
-
- //remove the row from the main array
- unset($array[$parent_name][$x][$child_name][$y]);
- }
-
- //increment the value
- $y++;
- }
- }
- }
-
- //increment the value
- $x++;
-
- }
- }
- }
- }
-
- //unset the original array
- unset($array);
-
- //get the $apps array from the installed apps from the core and mod directories
- if (count(self::$apps) == 0) {
- self::get_apps();
- }
-
- //search through all fields to see if toggle field exists
- foreach (self::$apps as $x => $app) {
- if (!empty($app['db']) && is_array($app['db'])) {
- foreach ($app['db'] as $y => $row) {
- if (is_array($row['table']['name'])) {
- $table_name = $row['table']['name']['text'];
- }
- else {
- $table_name = $row['table']['name'];
- }
- if ($table_name === self::TABLE_PREFIX.$parent_name) {
- if (is_array($row['fields'])) {
- foreach ($row['fields'] as $field) {
- if (isset($field['toggle'])) {
- $toggle_field = $field['name'];
- $toggle_values = $field['toggle'];
- }
+ //increment the value
+ $y++;
}
}
}
}
+
+ //increment the value
+ $x++;
+
+ }
+ }
+ }
+
+ //get the current data
+ if (count($copy_array) > 0) {
+
+ //build an array of tables, fields, and values
+ foreach ($copy_array as $table_name => $rows) {
+ foreach ($rows as $row) {
+ foreach ($row as $field_name => $field_value) {
+ $keys[$table_name][$field_name][] = $field_value;
+ }
}
}
- //if the toggle field and values are empty then set defaults
- if (empty($toggle_field)) {
- $toggle_field = self::singular($parent_name)."_enabled";
- }
- if (empty($toggle_values)) {
- $toggle_values[] = 'true';
- $toggle_values[] = 'false';
+ //unset the array
+ unset($array);
+
+ //use the array to get a copy of the parent data before deleting it
+ foreach ($copy_array as $table_name => $rows) {
+ foreach ($rows as $row) {
+ $table_name = self::sanitize($table_name);
+ $sql = "select * from " . self::TABLE_PREFIX . $table_name . " ";
+ $i = 0;
+ foreach ($row as $field_name => $field_value) {
+ if ($i == 0) {
+ $sql .= "where ";
+ } else {
+ $sql .= "and ";
+ }
+ $sql .= $field_name . " in ( ";
+ $i = 0;
+ foreach ($keys[$table_name][$field_name] as $field_value) {
+ $field_name = self::sanitize($field_name);
+ if ($i > 0) {
+ $sql .= " ,";
+ }
+ $sql .= " :" . $field_name . "_" . $i . " ";
+ $i++;
+ }
+ $sql .= ") ";
+ $i = 0;
+ foreach ($keys[$table_name][$field_name] as $field_value) {
+ $parameters[$field_name . '_' . $i] = $field_value;
+ $i++;
+ }
+ }
+ }
+
+ $results = $this->execute($sql, $parameters, 'all');
+ unset($parameters);
+ if (is_array($results)) {
+ $array[$table_name] = $results;
+ }
}
- //get the current values from the database
- foreach ($toggle_array as $table_name => $table) {
+ //add child data to the old array
+ foreach ($copy_array as $parent_name => $rows) {
+ //get relations array
+ $relations = self::get_relations($parent_name);
+
+ //loop through the rows
$x = 0;
- foreach($table as $row) {
- $child_name = self::sanitize($table_name);
- $child_key_name = self::singular($child_name)."_uuid";
+ foreach ($rows as $row) {
+ if (is_array($relations)) {
+ foreach ($relations as $relation) {
+ //set the child table
+ $child_table = $relation['table'];
- $array[$table_name][$x][$child_key_name] = $row[$child_key_name];
- $array[$table_name][$x][$toggle_field] = ($row[$toggle_field] === $toggle_values[0]) ? $toggle_values[1] : $toggle_values[0];
+ //remove the v_ prefix
+ if (substr($child_table, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX) {
+ $child_table = substr($child_table, strlen(self::TABLE_PREFIX));
+ }
+
+ //get the child data
+ $sql = "select * from " . self::TABLE_PREFIX . $child_table . " ";
+ $sql .= "where " . $relation['field'] . " = :" . $relation['field'];
+ $parameters[$relation['field']] = $row[$relation['field']];
+ $results = $this->execute($sql, $parameters, 'all');
+ unset($parameters);
+ if (is_array($results)) {
+ $array[$parent_name][$x][$child_table] = $results;
+ }
+ }
+ }
$x++;
}
}
- unset($toggle_array);
+ }
- //save the array
- return $this->save($array);
+ //update the parent and child keys
+ $checked = false;
+ $x = 0;
+ foreach ($array as $parent_name => $tables) {
+ if (is_array($tables)) {
+ foreach ($tables as $id => $row) {
- } //end function toggle
+ //prepare the variables
+ $parent_name = self::sanitize($parent_name);
+ $parent_key_name = self::singular($parent_name) . "_uuid";
+ $parent_key_value = uuid();
- /**
+ //update the parent key id
+ $array[$parent_name][$x][$parent_key_name] = $parent_key_value;
+
+ //set enabled
+ if (array_key_exists(self::singular($parent_name) . '_enabled', $array[$parent_name][$x])) {
+ $array[$parent_name][$x][self::singular($parent_name) . '_enabled'] = $row[self::singular($parent_name) . '_enabled'] === true || $row[self::singular($parent_name) . '_enabled'] == 'true' ? 'true' : 'false';
+ } elseif (array_key_exists('enabled', $array[$parent_name][$x])) {
+ $array[$parent_name][$x]['enabled'] = $row['enabled'] === true || $row['enabled'] == 'true' ? 'true' : 'false';
+ }
+
+ //add copy to the description
+ if (array_key_exists(self::singular($parent_name) . '_description', $array[$parent_name][$x])) {
+ $array[$parent_name][$x][self::singular($parent_name) . '_description'] = trim($array[$parent_name][$x][self::singular($parent_name) . '_description'] . ' ' . $suffix);
+ } elseif (array_key_exists('description', $array[$parent_name][$x])) {
+ $array[$parent_name][$x]['description'] = trim($array[$parent_name][$x]['description'] . ' ' . $suffix);
+ }
+
+ //loop through the fields
+ foreach ($row as $field_name => $field_value) {
+
+ //find the child tables
+ $y = 0;
+ if (is_array($field_value)) {
+ //prepare the variables
+ $child_name = self::sanitize($field_name);
+ $child_key_name = self::singular($child_name) . "_uuid";
+
+ //loop through the child rows
+ foreach ($field_value as $sub_row) {
+ //update the parent key id
+ $array[$parent_name][$x][$child_name][$y][$parent_key_name] = $parent_key_value;
+
+ //udpate the child key id
+ $array[$parent_name][$x][$child_name][$y][$child_key_name] = uuid();
+
+ //increment the value
+ $y++;
+ }
+ }
+ }
+
+ //increment the value
+ $x++;
+
+ }
+ }
+ }
+
+ //save the copy of the data
+ if (is_array($array) && count($array) > 0) {
+ $retval = $this->save($array);
+ unset($array);
+ }
+ return $retval;
+ }
+
+/**
*
- * @param array $array Three dimensional Array. The first dimension is the table name without the prefix 'v_'. Second dimension in the row value as int. Third dimension is the column name.
- * @param bool $transaction_save
+ *
NOTE:
- * There is no method in PDO that can reliably detect if the connection is active. Therefor, a lightweight
- * query is executed using the statement select 1.
- * @return bool True if the database is connected. False otherwise.
- */
- public function is_connected(): bool {
- try {
- $stmt = false;
- if ($this->db !== null) $stmt = $this->db->query('SELECT 1');
- return $stmt !== false;
- } catch (PDOException $ex) {
- //database is not connected
- return false;
- } catch (Exception $e) {
- //some other error has occurred so record it
+ //prepare the message array
$message['message'] = $e->getMessage();
$message['code'] = $e->getCode();
$message['line'] = $e->getLine();
@@ -3231,222 +3234,319 @@ class database {
$this->message = $message;
return false;
}
- return true;
+
+ //set the action if not set
+ if (empty($action)) {
+ if (!empty($old_array)) {
+ $transaction_type = 'update';
+ } else {
+ $transaction_type = 'add';
+ }
+ } else {
+ $transaction_type = $action;
+ }
+
+ //debug message
+ //echo "old\n";
+ //view_array($old_array, false);
+ //echo "new\n";
+ //view_array($new_array, false);
+ //exit;
+
+ //check to see if the database was updated; update the message code if needed
+ $database_updated = false;
+ if (!empty($this->message['code']) && $this->message['code'] === '200') {
+ $database_updated = true;
+ }
+ if (!$database_updated) {
+ foreach ($this->message['details'] as $row) {
+ if ($row['code'] === '200') {
+ $database_updated = true;
+ $message["code"] = '200';
+ break;
+ }
+ }
+ }
+
+ //log the transaction results
+ if ($transaction_save && $database_updated && file_exists($_SERVER["PROJECT_ROOT"] . "/app/database_transactions/app_config.php")) {
+ try {
+ //build the json string from the array
+ if (!empty($old_array)) {
+ $old_json = json_encode($old_array, JSON_PRETTY_PRINT);
+ }
+ if (!empty($new_array)) {
+ $new_json = json_encode($new_array, JSON_PRETTY_PRINT);
+ }
+
+ //insert the transaction into the database
+ $sql = "insert into " . self::TABLE_PREFIX . "database_transactions ";
+ $sql .= "(";
+ $sql .= "database_transaction_uuid, ";
+ if (isset($this->domain_uuid) && is_uuid($this->domain_uuid)) {
+ $sql .= "domain_uuid, ";
+ }
+ if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
+ $sql .= "user_uuid, ";
+ }
+ if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
+ $sql .= "app_uuid, ";
+ }
+ if (isset($this->app_name) && !empty($this->app_name)) {
+ $sql .= "app_name, ";
+ }
+ $sql .= "transaction_code, ";
+ $sql .= "transaction_address, ";
+ $sql .= "transaction_type, ";
+ $sql .= "transaction_date, ";
+ $sql .= "transaction_old, ";
+ $sql .= "transaction_new, ";
+ $sql .= "transaction_result ";
+ $sql .= ")";
+ $sql .= "values ";
+ $sql .= "(";
+ $sql .= "'" . uuid() . "', ";
+ if (isset($this->domain_uuid) && is_uuid($this->domain_uuid)) {
+ $sql .= ":domain_uuid, ";
+ }
+ if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
+ $sql .= ":user_uuid, ";
+ }
+ if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
+ $sql .= ":app_uuid, ";
+ }
+ if (isset($this->app_name) && !empty($this->app_name)) {
+ $sql .= ":app_name, ";
+ }
+ $sql .= "'" . $message["code"] . "', ";
+ $sql .= ":remote_address, ";
+ $sql .= "'" . $transaction_type . "', ";
+ $sql .= "now(), ";
+ if (!empty($old_json)) {
+ $sql .= ":transaction_old, ";
+ } else {
+ $sql .= "null, ";
+ }
+ if (!empty($new_json)) {
+ $sql .= ":transaction_new, ";
+ } else {
+ $sql .= "null, ";
+ }
+ $sql .= ":transaction_result ";
+ $sql .= ")";
+ $statement = $this->db->prepare($sql);
+ if (isset($this->domain_uuid) && is_uuid($this->domain_uuid)) {
+ $statement->bindParam(':domain_uuid', $this->domain_uuid);
+ }
+ if (isset($this->user_uuid) && is_uuid($this->user_uuid)) {
+ $statement->bindParam(':user_uuid', $this->user_uuid);
+ }
+ if (isset($this->app_uuid) && is_uuid($this->app_uuid)) {
+ $statement->bindParam(':app_uuid', $this->app_uuid);
+ }
+ if (isset($this->app_name) && !empty($this->app_name)) {
+ $statement->bindParam(':app_name', $this->app_name);
+ }
+ $statement->bindParam(':remote_address', $_SERVER['REMOTE_ADDR']);
+ if (!empty($old_json)) {
+ $old_json = json_encode($old_array, JSON_PRETTY_PRINT);
+ $statement->bindParam(':transaction_old', $old_json);
+ }
+ if (!empty($new_json)) {
+ $statement->bindParam(':transaction_new', $new_json);
+ }
+ $message = json_encode($this->message, JSON_PRETTY_PRINT);
+ $statement->bindParam(':transaction_result', $message);
+ $statement->execute();
+ unset($sql, $old_array, $old_json, $new_array, $new_json);
+ } catch (PDOException $e) {
+ $message['message'] = $e->getMessage();
+ $message['code'] = $e->getCode();
+ $message['line'] = $e->getLine();
+ $message['file'] = $e->getFile();
+ $message['trace'] = $e->getTraceAsString();
+ $message['debug'] = debug_backtrace();
+ $this->message = $message;
+ return false;
+ }
+ }
+ return $this->message;
}
- /**
- * Converts a plural English word to singular.
- * @param string $word English word
- * @return string Singular version of English word
- * @internal Moved to class to conserve resources.
+/**
+ * Toggles fields on a table using the toggle_field array values within the app object.
+ *
+ * @param array $array Three dimensional array. The first dimension is the table name without the prefix 'v_'.
+ * Second dimension in the row value as int. Third dimension is the column name.
+ *
+ * @return bool Returns true on success and false on failure.
+ * @depends database::save()
+ * @depends database::get_apps()
*/
- public static function singular(string $word) {
- //"-es" is used for words that end in "-x", "-s", "-z", "-sh", "-ch" in which case you add
- if (substr($word, -2) == "es") {
- if (substr($word, -4) == "sses") { // eg. 'addresses' to 'address'
- return substr($word,0,-2);
- }
- elseif (substr($word, -3) == "ses") { // eg. 'databases' to 'database' (necessary!)
- return substr($word,0,-1);
- }
- elseif (substr($word, -3) == "ies") { // eg. 'countries' to 'country'
- return substr($word,0,-3)."y";
- }
- elseif (substr($word, -3, 1) == "x") {
- return substr($word,0,-2);
- }
- elseif (substr($word, -3, 1) == "s") {
- return substr($word,0,-2);
- }
- elseif (substr($word, -3, 1) == "z") {
- return substr($word,0,-2);
- }
- elseif (substr($word, -4, 2) == "sh") {
- return substr($word,0,-2);
- }
- elseif (substr($word, -4, 2) == "ch") {
- return substr($word,0,-2);
- }
- else {
- return rtrim($word, "s");
+ public function toggle(array $array) {
+
+ //return the array
+ if (!is_array($array)) {
+ return false;
+ }
+
+ //set the message id
+ $m = 0;
+
+ //loop through the array
+ if (!empty($array) && is_array($array)) {
+ $x = 0;
+ foreach ($array as $parent_name => $tables) {
+ if (!empty($tables) && is_array($tables)) {
+ foreach ($tables as $id => $row) {
+
+ //prepare the variables
+ $parent_name = self::sanitize($parent_name);
+ $parent_key_name = self::singular($parent_name) . "_uuid";
+
+ //build the toggle array
+ if (!empty($row['checked']) && $row['checked'] == 'true') {
+ //toggle the field value
+ //$toggle_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
+ $toggle_array[$parent_name][$x] = $row;
+
+ //remove the row from the main array
+ unset($array[$parent_name][$x]);
+ }
+
+ //loop through the fields
+ foreach ($row as $field_name => $field_value) {
+
+ //find the child tables
+ $y = 0;
+ if (!empty($field_value) && is_array($field_value)) {
+ //prepare the variables
+ $child_name = self::sanitize($field_name);
+ $child_key_name = self::singular($child_name) . "_uuid";
+
+ //loop through the child rows
+ foreach ($field_value as $sub_row) {
+
+ //build the delete array
+ if ($sub_row['checked'] == 'true') {
+ //delete the child data
+ $delete_array[$child_name][$y][$child_key_name] = $sub_row[$child_key_name];
+
+ //remove the row from the main array
+ unset($array[$parent_name][$x][$child_name][$y]);
+ }
+
+ //increment the value
+ $y++;
+ }
+ }
+ }
+
+ //increment the value
+ $x++;
+
+ }
+ }
}
}
- else {
- return rtrim($word, "s");
+
+ //unset the original array
+ unset($array);
+
+ //get the $apps array from the installed apps from the core and mod directories
+ if (count(self::$apps) == 0) {
+ self::get_apps();
}
+
+ //search through all fields to see if toggle field exists
+ foreach (self::$apps as $x => $app) {
+ if (!empty($app['db']) && is_array($app['db'])) {
+ foreach ($app['db'] as $y => $row) {
+ if (is_array($row['table']['name'])) {
+ $table_name = $row['table']['name']['text'];
+ } else {
+ $table_name = $row['table']['name'];
+ }
+ if ($table_name === self::TABLE_PREFIX . $parent_name) {
+ if (is_array($row['fields'])) {
+ foreach ($row['fields'] as $field) {
+ if (isset($field['toggle'])) {
+ $toggle_field = $field['name'];
+ $toggle_values = $field['toggle'];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //if the toggle field and values are empty then set defaults
+ if (empty($toggle_field)) {
+ $toggle_field = self::singular($parent_name) . "_enabled";
+ }
+ if (empty($toggle_values)) {
+ $toggle_values[] = 'true';
+ $toggle_values[] = 'false';
+ }
+
+ //get the current values from the database
+ foreach ($toggle_array as $table_name => $table) {
+ $x = 0;
+ foreach ($table as $row) {
+ $child_name = self::sanitize($table_name);
+ $child_key_name = self::singular($child_name) . "_uuid";
+
+ $array[$table_name][$x][$child_key_name] = $row[$child_key_name];
+ $array[$table_name][$x][$toggle_field] = ($row[$toggle_field] === $toggle_values[0]) ? $toggle_values[1] : $toggle_values[0];
+ $x++;
+ }
+ }
+ unset($toggle_array);
+
+ //save the array
+ return $this->save($array);
+
}
/**
- * Gets the $apps array from the installed apps from the core and mod directories and writes it to self::$apps overwriting previous values.
- * @uses $_SERVER['DOCUMENT_ROOT'] Global variable
- * @uses PROJECT_PATH Global variable
+ * Gets the $apps array from the installed apps from the core and mod directories and writes it to self::$apps
+ * overwriting previous values.
+ *
* @return null Does not return any values
+ * @uses PROJECT_PATH Global variable
+ * @uses $_SERVER['DOCUMENT_ROOT'] Global variable
* @internal Moved to class to conserve resources.
*/
public static function get_apps() {
//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;
- if (is_array($config_list)) {
- foreach ($config_list as $config_path) {
- include($config_path);
- $x++;
- }
- }
- self::$apps = $apps;
- }
-
- /**
- * Returns the depth of an array
- * @param array $array Reference to array
- * @return int Depth of array
- * @internal Moved to class to conserve resources.
- */
- public static function array_depth(array &$array) {
- $depth = 0;
- if (is_array($array)) {
- $depth++;
- foreach ($array as $value) {
- if (is_array($value)) {
- $depth = self::array_depth($value) + 1;
- }
- }
- }
- return $depth;
- }
-
- /**
- * Searches through all fields to see if domain_uuid exists
- * @param string $name
- * @uses self::$apps directly
- * @return boolean true on success and false on failure
- * @see database::get_apps()
- */
- public static function domain_uuid_exists($name) {
- //get the $apps array from the installed apps from the core and mod directories
- if (count(self::$apps) == 0) {
- self::get_apps();
- }
-
- //search through all fields to see if domain_uuid exists
- foreach (self::$apps as $x => &$app) {
- if (is_array($app['db'])) {
- foreach ($app['db'] as $y => $row) {
- if (is_array($row['table']['name'])) {
- $table_name = $row['table']['name']['text'];
- }
- else {
- $table_name = $row['table']['name'];
- }
- if ($table_name === self::TABLE_PREFIX.$name) {
- if (is_array($row['fields'])) {
- foreach ($row['fields'] as $field) {
- if ($field['name'] == "domain_uuid") {
- return true;
- }
- } //foreach
- } //is array
- }
- } //foreach
- } //is array
- } //foreach
-
- //not found
- return false;
- }
-
- /**
- * Get Relations searches through all fields to find relations
- * @param string $schema Table name
- * @return array Returns array or false
- * @internal Moved to class to conserve resources.
- */
- public static function get_relations($schema) {
-
- //remove the v_ prefix
- if (substr($schema, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX) {
- $schema = substr($schema, strlen(self::TABLE_PREFIX));
- }
-
- //sanitize the values
- $schema = self::sanitize($schema);
-
- //get the apps array
- $config_list = [];
- $directories = ["core", "app"];
- $applications = [$schema, self::singular($schema)];
- foreach ($directories as $directory) {
- foreach ($applications as $application) {
- $path = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/$directory/$application/app_config.php";
- $app_config_files = glob($path);
- if ($app_config_files !== false) {
- $config_list = array_merge($config_list, $app_config_files);
- }
- }
- }
- $x = 0;
+ $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
+ $x = 0;
+ if (is_array($config_list)) {
foreach ($config_list as $config_path) {
include($config_path);
$x++;
}
-
- //search through all fields to find relations
- if (!empty($apps) && is_array($apps)) {
- foreach ($apps as $x => $app) {
- foreach ($app['db'] as $y => $row) {
- foreach ($row['fields'] as $z => $field) {
- if (!empty($field['deprecated']) && $field['deprecated'] != "true") {
- if (!empty($field['key']['type']) && $field['key']['type'] == "foreign") {
- if ($row['table']['name'] == self::TABLE_PREFIX.$schema || $field['key']['reference']['table'] == self::TABLE_PREFIX.$schema) {
- //get the field name
- if (!empty($field['name']) && is_array($field['name'])) {
- $field_name = trim($field['name']['text']);
- }
- else {
- $field_name = trim($field['name']);
- }
- //build the array
- $relations[$i]['table'] = $row['table']['name'];
- $relations[$i]['field'] = $field_name;
- $relations[$i]['key']['type'] = $field['key']['type'];
- $relations[$i]['key']['table'] = $field['key']['reference']['table'];
- $relations[$i]['key']['field'] = $field['key']['reference']['field'];
- if (isset($field['key']['reference']['action'])) {
- $relations[$i]['key']['action'] = $field['key']['reference']['action'];
- }
- //increment the value
- $i++;
- }
- }
- }
- unset($field_name);
- }
- }
- }
- }
-
- //return the array
- if (!empty($relations) && is_array($relations)) {
- return $relations;
- } else {
- return false;
- }
+ }
+ self::$apps = $apps;
}
/**
* Gets a list of database views from the file system.
+ *
* @param string $action options: list, create, drop
+ *
* @return array shows list of views, list of views that were updated
*/
public function views(string $action) {
$files = glob(dirname(__DIR__, 2) . "/*/*/resources/database/views/*.php");
- foreach($files as $id => $file) {
- $view = array();
+ foreach ($files as $id => $file) {
+ $view = [];
try {
include $file;
$views[$id] = $view;
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$views[$id]['error'] = $e->getMessage();
} finally {
$views[$id]['file'] = $file;
@@ -3460,8 +3560,8 @@ class database {
//update views
if ($action === 'create') {
- $array = array();
- foreach($views as $id => $row) {
+ $array = [];
+ foreach ($views as $id => $row) {
if (!empty($row['name']) && !empty($row['sql'])) {
//set the variables
$view_name = $row['name'];
@@ -3471,15 +3571,14 @@ class database {
//$view_description = $row['description'];
//create and run the view sql
- $sql = "CREATE OR REPLACE VIEW ".$view_name." AS (\n";
- $sql .= $view_sql."\n";
+ $sql = "CREATE OR REPLACE VIEW " . $view_name . " AS (\n";
+ $sql .= $view_sql . "\n";
$sql .= ")\n";
$this->execute($sql);
//build the return array
$views[$id]['result'] = $this->message;
- }
- else {
+ } else {
//build the return array
$views[$id]['result'] = 'Name or SQL empty';
}
@@ -3491,20 +3590,19 @@ class database {
//drop views
if ($action === 'drop') {
- $array = array();
- foreach($views as $id => $row) {
+ $array = [];
+ foreach ($views as $id => $row) {
if (!empty($row['name'])) {
//set the variables
$view_name = $row['name'];
//create and run the view sql
- $sql = "DROP VIEW ".$view_name.";";
+ $sql = "DROP VIEW " . $view_name . ";";
$this->execute($sql);
//build the return array
$views[$id]['result'] = 'Dropped';
- }
- else {
+ } else {
//build the return array
$views[$id]['result'] = 'Name or SQL empty';
}
@@ -3515,90 +3613,38 @@ class database {
}
}
- /**
- * Returns a sanitized string value safe for database or table name.
- * @param string $value To be sanitized
- * @return string Sanitized using preg_replace('#[^a-zA-Z0-9_\-]#', '')
- * @see preg_replace()
- */
- public static function sanitize(string $value) {
- return preg_replace('#[^a-zA-Z0-9_\-]#', '', $value);
- }
-
- /**
- * Returns a new connected database object.
- *
This allows a shortcut for a common syntax. For more information
- * on how the connection happens see {@link database::__construct()} and
- * {@link database::connect()}
- *
Usage:
- * $database_object = database::new();
- * @return database new instance of database object already connected
- * @see database::__construct()
- * @see database::connect()
- */
- public static function new(array $params = []) {
-
- //re-use the database connection
- if (self::$database === null) {
- self::$database = new database($params);
- if (!self::$database->is_connected()) {
- self::$database->connect();
- }
- }
-
- //set the user_uuid
- if (!empty($params['user_uuid'])) {
- //use the parameter as the first priority when available
- self::$database->user_uuid = $params['user_uuid'];
- } elseif (!empty($_SESSION['user_uuid'])) {
- //use the session when available
- self::$database->user_uuid = $_SESSION['user_uuid'];
- }
-
- //set the domain_uuid
- if (!empty($params['domain_uuid'])) {
- //use the parameter as the first priority when available
- self::$database->domain_uuid = $params['domain_uuid'];
- } elseif (!empty($_SESSION['domain_uuid'])) {
- //use the session when available
- self::$database->domain_uuid = $_SESSION['domain_uuid'];
- }
-
- return self::$database;
- }
-
} //class database
//addtitional functions for sqlite
- if (!function_exists('php_md5')) {
- function php_md5($string) {
- return md5($string);
- }
+if (!function_exists('php_md5')) {
+ function php_md5($string) {
+ return md5($string);
}
+}
- if (!function_exists('php_unix_time_stamp')) {
- function php_unix_time_stamp($string) {
- return strtotime($string);
- }
+if (!function_exists('php_unix_time_stamp')) {
+ function php_unix_time_stamp($string) {
+ return strtotime($string);
}
+}
- if (!function_exists('php_now')) {
- function php_now() {
- return date("Y-m-d H:i:s");
- }
+if (!function_exists('php_now')) {
+ function php_now() {
+ return date("Y-m-d H:i:s");
}
+}
- if (!function_exists('php_left')) {
- function php_left($string, $num) {
- return substr($string, 0, $num);
- }
+if (!function_exists('php_left')) {
+ function php_left($string, $num) {
+ return substr($string, 0, $num);
}
+}
- if (!function_exists('php_right')) {
- function php_right($string, $num) {
- return substr($string, (strlen($string)-$num), strlen($string));
- }
+if (!function_exists('php_right')) {
+ function php_right($string, $num) {
+ return substr($string, (strlen($string) - $num), strlen($string));
}
+}
/*
//example usage
diff --git a/resources/classes/domains.php b/resources/classes/domains.php
index 4d3161bb60..9407ada73b 100644
--- a/resources/classes/domains.php
+++ b/resources/classes/domains.php
@@ -38,8 +38,8 @@ class domains {
const app_uuid = '8b91605b-f6d2-42e6-a56d-5d1ded01bb44';
/**
- * declare the variables
- */
+ * declare the variables
+ */
private $name;
private $table;
private $toggle_field;
@@ -48,37 +48,47 @@ class domains {
/**
* 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;
/**
- * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array
+ * User 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 $user_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
+ * 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;
/**
- * called when the object is created
+ * 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($setting_array = []) {
//assign the variables
$this->name = 'domain';
$this->table = 'domains';
$this->toggle_field = 'domain_enabled';
- $this->toggle_values = ['true','false'];
+ $this->toggle_values = ['true', 'false'];
$this->location = 'domains.php';
//set the domain and user uuids
@@ -101,750 +111,775 @@ class domains {
}
/**
- * delete rows from the database
+ * get all enabled domains
+ *
+ * @returns array all enabled domains with uuid as array key
*/
- public function delete($records) {
- if (permission_exists($this->name.'_delete')) {
+ public static function enabled() {
- //add multi-lingual support
- $language = new text;
- $text = $language->get();
+ //define database as global
+ global $database;
- //validate the token
- $token = new token;
- if (!$token->validate($_SERVER['PHP_SELF'])) {
- message::add($text['message-invalid_token'],'negative');
- header('Location: '.$this->location);
- exit;
- }
+ //define default return value
+ $domains = [];
- //delete multiple records
- if (is_array($records) && @sizeof($records) != 0) {
- //build the delete array
- foreach ($records as $record) {
- //add to the array
- if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
- //set the uuid
- $id = $record['uuid'];
-
- //get the domain using the id
- $sql = "select domain_name from v_domains ";
- $sql .= "where domain_uuid = :domain_uuid ";
- $parameters['domain_uuid'] = $id;
- $domain_name = $this->database->select($sql, $parameters, 'column');
- unset($sql, $parameters);
-
- //get the domain settings
- $sql = "select * from v_domain_settings ";
- $sql .= "where domain_uuid = :domain_uuid ";
- $sql .= "and domain_setting_enabled = 'true' ";
- $parameters['domain_uuid'] = $id;
- $result = $this->database->select($sql, $parameters, 'all');
- unset($sql, $parameters);
-
- if (is_array($result) && sizeof($result) != 0) {
- foreach ($result as $row) {
- $name = $row['domain_setting_name'];
- $category = $row['domain_setting_category'];
- $subcategory = $row['domain_setting_subcategory'];
- if ($subcategory != '') {
- if ($name == "array") {
- $_SESSION[$category][] = $row['default_setting_value'];
- }
- else {
- $_SESSION[$category][$name] = $row['default_setting_value'];
- }
- }
- else {
- if ($name == "array") {
- $_SESSION[$category][$subcategory][] = $row['default_setting_value'];
- }
- else {
- $_SESSION[$category][$subcategory]['uuid'] = $row['default_setting_uuid'];
- $_SESSION[$category][$subcategory][$name] = $row['default_setting_value'];
- }
- }
- }
- }
- unset($result, $row);
-
- //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;
- if (isset($config_list)) foreach ($config_list as $config_path) {
- include($config_path);
- $x++;
- }
-
- //delete the domain data from all tables in the database
- if (isset($apps)) foreach ($apps as $app) {
- if (isset($app['db'])) foreach ($app['db'] as $row) {
- if (is_array($row['table']['name'])) {
- $table_name = $row['table']['name']['text'];
- if (defined('STDIN')) {
- echo "
".print_r($table_name, 1)."
\n";
- }
- }
- else {
- $table_name = $row['table']['name'];
- }
- if ($table_name !== "v" && isset($row['fields'])) {
- foreach ($row['fields'] as $field) {
- if ($field['name'] == 'domain_uuid' && $table_name != 'v_domains') {
- $sql = "delete from ".$table_name." where domain_uuid = :domain_uuid ";
- $parameters['domain_uuid'] = $id;
- $this->database->app_name = 'domain_settings';
- $this->database->app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71';
- $this->database->execute($sql, $parameters);
- unset($sql, $parameters);
- }
- }
- }
- }
- }
-
- //delete the directories
- if (!empty($domain_name)) {
- //set the needle
- if (count($_SESSION["domains"]) > 1) {
- $v_needle = 'v_'.$domain_name.'_';
- }
- else {
- $v_needle = 'v_';
- }
-
- //delete the dialplan
- @unlink($_SESSION['switch']['dialplan']['dir'].'/'.$domain_name.'.xml');
- if (!empty($_SESSION['switch']['dialplan']['dir'])) {
- system('rm -rf '.$_SESSION['switch']['dialplan']['dir'].'/'.$domain_name);
- }
-
- //delete the dialplan public
- @unlink($_SESSION['switch']['dialplan']['dir'].'/public/'.$domain_name.'.xml');
- if (!empty($_SESSION['switch']['dialplan']['dir'])) {
- system('rm -rf '.$_SESSION['switch']['dialplan']['dir'].'/public/'.$domain_name);
- }
-
- //delete the extension
- @unlink($_SESSION['switch']['extensions']['dir'].'/'.$domain_name.'.xml');
- if (!empty($_SESSION['switch']['extensions']['dir'])) {
- system('rm -rf '.$_SESSION['switch']['extensions']['dir'].'/'.$domain_name);
- }
-
- //delete fax
- if (!empty($_SESSION['switch']['storage']['dir'])) {
- system('rm -rf '.$_SESSION['switch']['storage']['dir'].'/fax/'.$domain_name);
- }
-
- //delete the gateways
- if (!empty($_SESSION['switch']['sip_profiles']['dir'])) {
- if ($dh = opendir($_SESSION['switch']['sip_profiles']['dir'])) {
- $files = Array();
- while ($file = readdir($dh)) {
- if ($file != "." && $file != ".." && $file[0] != '.') {
- if (is_dir($dir . "/" . $file)) {
- //this is a directory do nothing
- }
- else {
- //check if file extension is xml
- if (strpos($file, $v_needle) !== false && substr($file,-4) == '.xml') {
- @unlink($_SESSION['switch']['sip_profiles']['dir']."/".$file);
- }
- }
- }
- }
- closedir($dh);
- }
- }
-
- //delete the ivr menu
- if (!empty($_SESSION['switch']['conf']['dir'])) {
- if ($dh = opendir($_SESSION['switch']['conf']['dir']."/ivr_menus")) {
- $files = Array();
- while ($file = readdir($dh)) {
- if ($file != "." && $file != ".." && $file[0] != '.') {
- if (!empty($dir) && !empty($file) && is_dir($dir."/".$file)) {
- //this is a directory
- }
- else {
- if (strpos($file, $v_needle) !== false && substr($file,-4) == '.xml') {
- @unlink($_SESSION['switch']['conf']['dir']."/ivr_menus/".$file);
- }
- }
- }
- }
- closedir($dh);
- }
- }
-
- //delete the recordings
- if (!empty($_SESSION['switch']['recordings']['dir'])) {
- system('rm -rf '.$_SESSION['switch']['recordings']['dir'].'/'.$_SESSION['domain_name'].'/'.$domain_name);
- }
-
- //delete voicemail
- if (!empty($_SESSION['switch']['voicemail']['dir'])) {
- system('rm -rf '.$_SESSION['switch']['voicemail']['dir'].'/'.$domain_name);
- }
- }
-
- //apply settings reminder
- $_SESSION["reload_xml"] = true;
-
- //remove the domain from domains session array
- unset($_SESSION["domains"][$id]);
-
- //add domain uuid to array for deletion below
- $domain_array['domains'][] = ['domain_uuid'=>$id];
- }
- }
-
- //delete the checked rows
- if (is_array($domain_array) && @sizeof($domain_array) != 0) {
- //execute delete
- $this->database->delete($domain_array);
-
- //set message
- message::add($text['message-delete']);
-
- //reload default/domain settings
- $this->set();
- }
- unset($records);
- }
+ //get the domains from the database
+ $sql = "select * from v_domains ";
+ $sql .= "where domain_enabled = true ";
+ $sql .= "order by domain_name asc; ";
+ $result = $database->select($sql, null, 'all');
+ if (!empty($result)) {
+ foreach ($result as $row) {
+ $domains[$row['domain_uuid']] = $row;
+ }
}
+
+ //return the domains array
+ return $domains;
}
/**
- * toggle a field between two values
+ * get all disabled domains
+ *
+ * @returns array all disabled domains with uuid as array key
+ */
+ public static function disabled() {
+
+ //define database as global
+ global $database;
+
+ //define default return value
+ $domains = [];
+
+ //get the domains from the database
+ $sql = "select * from v_domains ";
+ $sql .= "where domain_enabled = false ";
+ $sql .= "order by domain_name asc; ";
+ $result = $database->select($sql, null, 'all');
+ if (!empty($result)) {
+ foreach ($result as $row) {
+ $domains[$row['domain_uuid']] = $row;
+ }
+ }
+
+ //return the domains array
+ return $domains;
+ }
+
+ /**
+ * 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')) {
+ if (permission_exists($this->name . '_edit')) {
//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->location);
- exit;
- }
+ $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);
+ 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
+ * 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')) {
+ if (permission_exists($this->name . '_add')) {
//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->location);
- exit;
- }
+ $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) {
+ 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']."'";
- }
- }
+ //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 (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, 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][$this->name.'_description'] = trim($row[$this->name.'_description']).' ('.$text['label-copy'].')';
-
- //increment the id
- $x++;
+ //create the array from existing data
+ if (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, 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;
}
}
- unset($sql, $parameters, $rows, $row);
+
+ //copy data
+ $array[$this->table][$x] = $row;
+
+ //add copy to the description
+ $array[$this->table][$x][$this->name . '_uuid'] = uuid();
+ $array[$this->table][$x][$this->name . '_description'] = trim($row[$this->name . '_description']) . ' (' . $text['label-copy'] . ')';
+
+ //increment the id
+ $x++;
}
-
- //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);
+ }
}
}
/**
- * add default, domain and user settings to the session array
+ * Upgrade function to apply necessary changes and settings.
+ *
+ * @return void
+ */
+ public function upgrade() {
+
+ //add multi-lingual support
+ $language = new text;
+ $text = $language->get(null, 'core/upgrade');
+
+ //includes files
+ require dirname(__DIR__, 2) . "/resources/require.php";
+
+ //add missing default settings
+ $this->settings();
+
+ //save the database object to be used by app_defaults.php
+ $database = $this->database;
+
+ //get the variables
+ $config = new config;
+ $config_path = $config->config_file;
+
+ //get the list of installed apps from the core and app directories (note: GLOB_BRACE doesn't work on some systems)
+ $config_list_1 = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
+ $config_list_2 = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_menu.php");
+ $config_list = array_merge((array)$config_list_1, (array)$config_list_2);
+ unset($config_list_1, $config_list_2);
+ $x = 0;
+ foreach ($config_list as $config_path) {
+ $app_path = dirname($config_path);
+ $app_path = preg_replace('/\A.*(\/.*\/.*)\z/', '$1', $app_path);
+ include($config_path);
+ $x++;
+ }
+
+ //get the domains
+ $sql = "select * from v_domains ";
+ $domains = $this->database->select($sql, null, 'all');
+ unset($sql);
+
+ //get the list of installed apps from the core and mod directories
+ $default_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_defaults.php");
+
+ //loop through all domains
+ $domains_processed = 1;
+ foreach ($domains as $domain) {
+ //get the values from database and set them as php variables
+ $domain_uuid = $domain["domain_uuid"];
+ $domain_name = $domain["domain_name"];
+
+ //get the context
+ $context = $domain_name;
+
+ //get the email queue settings
+ $settings = new settings(["database" => $this->database, "domain_uuid" => $domain_uuid]);
+
+ //run the php code in app_defaults.php
+ foreach ($default_list as $default_path) {
+ include($default_path);
+ }
+
+ //track the number of domains processed
+ $domains_processed++;
+ }
+
+ } //end upgrade method
+
+ /**
+ * Get the default settings for the application.
+ *
+ * This function first retrieves an array of default setting UUIDs from the database,
+ * then checks each app_config.php file in the project directory to see if they contain
+ * any default settings that are not already included in the UUID list. If so, it adds
+ * them to the array and attempts to insert them into the database.
+ *
+ * @return void
+ */
+ public function settings() {
+
+ //includes files
+ require dirname(__DIR__, 2) . "/resources/require.php";
+
+ //get an array of the default settings UUIDs
+ $sql = "select * from v_default_settings ";
+ $result = $this->database->select($sql, null, 'all');
+ foreach ($result as $row) {
+ $setting[$row['default_setting_uuid']] = 1;
+ }
+ unset($sql);
+
+ //get the list of default settings
+ $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
+ $x = 0;
+ foreach ($config_list as $config_path) {
+ include($config_path);
+ $x++;
+ }
+ $x = 0;
+ foreach ($apps as $app) {
+ if (isset($app['default_settings']) && is_array($app['default_settings'])) {
+ foreach ($app['default_settings'] as $row) {
+ if (!isset($setting[$row['default_setting_uuid']])) {
+ $array['default_settings'][$x] = $row;
+ $array['default_settings'][$x]['app_uuid'] = $app['uuid'];
+ $x++;
+ }
+ }
+ }
+ }
+
+ //add the missing default settings
+ if (isset($array) && is_array($array) && count($array) > 0) {
+ //grant temporary permissions
+ $p = permissions::new();
+ $p->add('default_setting_add', 'temp');
+
+ //execute insert
+ $this->database->app_name = 'default_settings';
+ $this->database->app_uuid = '2c2453c0-1bea-4475-9f44-4d969650de09';
+ $this->database->save($array, false);
+ unset($array);
+
+ //revoke temporary permissions
+ $p->delete('default_setting_add', 'temp');
+ }
+
+ } //end settings method
+
+ /**
+ * 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();
+
+ //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 $record) {
+ //add to the array
+ if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
+ //set the uuid
+ $id = $record['uuid'];
+
+ //get the domain using the id
+ $sql = "select domain_name from v_domains ";
+ $sql .= "where domain_uuid = :domain_uuid ";
+ $parameters['domain_uuid'] = $id;
+ $domain_name = $this->database->select($sql, $parameters, 'column');
+ unset($sql, $parameters);
+
+ //get the domain settings
+ $sql = "select * from v_domain_settings ";
+ $sql .= "where domain_uuid = :domain_uuid ";
+ $sql .= "and domain_setting_enabled = 'true' ";
+ $parameters['domain_uuid'] = $id;
+ $result = $this->database->select($sql, $parameters, 'all');
+ unset($sql, $parameters);
+
+ if (is_array($result) && sizeof($result) != 0) {
+ foreach ($result as $row) {
+ $name = $row['domain_setting_name'];
+ $category = $row['domain_setting_category'];
+ $subcategory = $row['domain_setting_subcategory'];
+ if ($subcategory != '') {
+ if ($name == "array") {
+ $_SESSION[$category][] = $row['default_setting_value'];
+ } else {
+ $_SESSION[$category][$name] = $row['default_setting_value'];
+ }
+ } else {
+ if ($name == "array") {
+ $_SESSION[$category][$subcategory][] = $row['default_setting_value'];
+ } else {
+ $_SESSION[$category][$subcategory]['uuid'] = $row['default_setting_uuid'];
+ $_SESSION[$category][$subcategory][$name] = $row['default_setting_value'];
+ }
+ }
+ }
+ }
+ unset($result, $row);
+
+ //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;
+ if (isset($config_list)) foreach ($config_list as $config_path) {
+ include($config_path);
+ $x++;
+ }
+
+ //delete the domain data from all tables in the database
+ if (isset($apps)) foreach ($apps as $app) {
+ if (isset($app['db'])) foreach ($app['db'] as $row) {
+ if (is_array($row['table']['name'])) {
+ $table_name = $row['table']['name']['text'];
+ if (defined('STDIN')) {
+ echo "
" . print_r($table_name, 1) . "
\n";
+ }
+ } else {
+ $table_name = $row['table']['name'];
+ }
+ if ($table_name !== "v" && isset($row['fields'])) {
+ foreach ($row['fields'] as $field) {
+ if ($field['name'] == 'domain_uuid' && $table_name != 'v_domains') {
+ $sql = "delete from " . $table_name . " where domain_uuid = :domain_uuid ";
+ $parameters['domain_uuid'] = $id;
+ $this->database->app_name = 'domain_settings';
+ $this->database->app_uuid = 'b31e723a-bf70-670c-a49b-470d2a232f71';
+ $this->database->execute($sql, $parameters);
+ unset($sql, $parameters);
+ }
+ }
+ }
+ }
+ }
+
+ //delete the directories
+ if (!empty($domain_name)) {
+ //set the needle
+ if (count($_SESSION["domains"]) > 1) {
+ $v_needle = 'v_' . $domain_name . '_';
+ } else {
+ $v_needle = 'v_';
+ }
+
+ //delete the dialplan
+ @unlink($_SESSION['switch']['dialplan']['dir'] . '/' . $domain_name . '.xml');
+ if (!empty($_SESSION['switch']['dialplan']['dir'])) {
+ system('rm -rf ' . $_SESSION['switch']['dialplan']['dir'] . '/' . $domain_name);
+ }
+
+ //delete the dialplan public
+ @unlink($_SESSION['switch']['dialplan']['dir'] . '/public/' . $domain_name . '.xml');
+ if (!empty($_SESSION['switch']['dialplan']['dir'])) {
+ system('rm -rf ' . $_SESSION['switch']['dialplan']['dir'] . '/public/' . $domain_name);
+ }
+
+ //delete the extension
+ @unlink($_SESSION['switch']['extensions']['dir'] . '/' . $domain_name . '.xml');
+ if (!empty($_SESSION['switch']['extensions']['dir'])) {
+ system('rm -rf ' . $_SESSION['switch']['extensions']['dir'] . '/' . $domain_name);
+ }
+
+ //delete fax
+ if (!empty($_SESSION['switch']['storage']['dir'])) {
+ system('rm -rf ' . $_SESSION['switch']['storage']['dir'] . '/fax/' . $domain_name);
+ }
+
+ //delete the gateways
+ if (!empty($_SESSION['switch']['sip_profiles']['dir'])) {
+ if ($dh = opendir($_SESSION['switch']['sip_profiles']['dir'])) {
+ $files = [];
+ while ($file = readdir($dh)) {
+ if ($file != "." && $file != ".." && $file[0] != '.') {
+ if (is_dir($dir . "/" . $file)) {
+ //this is a directory do nothing
+ } else {
+ //check if file extension is xml
+ if (strpos($file, $v_needle) !== false && substr($file, -4) == '.xml') {
+ @unlink($_SESSION['switch']['sip_profiles']['dir'] . "/" . $file);
+ }
+ }
+ }
+ }
+ closedir($dh);
+ }
+ }
+
+ //delete the ivr menu
+ if (!empty($_SESSION['switch']['conf']['dir'])) {
+ if ($dh = opendir($_SESSION['switch']['conf']['dir'] . "/ivr_menus")) {
+ $files = [];
+ while ($file = readdir($dh)) {
+ if ($file != "." && $file != ".." && $file[0] != '.') {
+ if (!empty($dir) && !empty($file) && is_dir($dir . "/" . $file)) {
+ //this is a directory
+ } else {
+ if (strpos($file, $v_needle) !== false && substr($file, -4) == '.xml') {
+ @unlink($_SESSION['switch']['conf']['dir'] . "/ivr_menus/" . $file);
+ }
+ }
+ }
+ }
+ closedir($dh);
+ }
+ }
+
+ //delete the recordings
+ if (!empty($_SESSION['switch']['recordings']['dir'])) {
+ system('rm -rf ' . $_SESSION['switch']['recordings']['dir'] . '/' . $_SESSION['domain_name'] . '/' . $domain_name);
+ }
+
+ //delete voicemail
+ if (!empty($_SESSION['switch']['voicemail']['dir'])) {
+ system('rm -rf ' . $_SESSION['switch']['voicemail']['dir'] . '/' . $domain_name);
+ }
+ }
+
+ //apply settings reminder
+ $_SESSION["reload_xml"] = true;
+
+ //remove the domain from domains session array
+ unset($_SESSION["domains"][$id]);
+
+ //add domain uuid to array for deletion below
+ $domain_array['domains'][] = ['domain_uuid' => $id];
+ }
+ }
+
+ //delete the checked rows
+ if (is_array($domain_array) && @sizeof($domain_array) != 0) {
+ //execute delete
+ $this->database->delete($domain_array);
+
+ //set message
+ message::add($text['message-delete']);
+
+ //reload default/domain settings
+ $this->set();
+ }
+ unset($records);
+ }
+ }
+ }
+
+ /**
+ * set domain settings
+ *
+ * This method retrieves domain and user settings from the database,
+ * unsets previous domain settings, sets default settings as session variables,
+ * and updates the time zone based on the domain's time zone setting.
+ *
+ * @return void
*/
public function set() {
//get previous domain settings
- if (isset($_SESSION["previous_domain_uuid"])) {
- $sql = "select * from v_domain_settings ";
- $sql .= "where domain_uuid = :previous_domain_uuid ";
- $sql .= "and domain_setting_enabled = 'true' ";
- $sql .= " order by domain_setting_order asc ";
- $parameters['previous_domain_uuid'] = $_SESSION["previous_domain_uuid"];
- $result = $this->database->select($sql, $parameters, 'all');
- unset($sql, $parameters);
-
- //unset previous domain settings
- foreach ($result as $row) {
- if ($row['domain_setting_category'] != 'user') { //skip off-limit categories
- unset($_SESSION[$row['domain_setting_category']][$row['domain_setting_subcategory']]);
- }
- }
- unset($_SESSION["previous_domain_uuid"]);
- }
-
- //get the default settings
- $sql = "select * from v_default_settings ";
- $sql .= "order by default_setting_order asc ";
- $result = $this->database->select($sql, null, 'all');
+ if (isset($_SESSION["previous_domain_uuid"])) {
+ $sql = "select * from v_domain_settings ";
+ $sql .= "where domain_uuid = :previous_domain_uuid ";
+ $sql .= "and domain_setting_enabled = 'true' ";
+ $sql .= " order by domain_setting_order asc ";
+ $parameters['previous_domain_uuid'] = $_SESSION["previous_domain_uuid"];
+ $result = $this->database->select($sql, $parameters, 'all');
unset($sql, $parameters);
- //unset all settings
+ //unset previous domain settings
foreach ($result as $row) {
- if ($row['default_setting_category'] != 'user') { //skip off-limit categories
- unset($_SESSION[$row['default_setting_category']][$row['default_setting_subcategory']]);
+ if ($row['domain_setting_category'] != 'user') { //skip off-limit categories
+ unset($_SESSION[$row['domain_setting_category']][$row['domain_setting_subcategory']]);
+ }
+ }
+ unset($_SESSION["previous_domain_uuid"]);
+ }
+
+ //get the default settings
+ $sql = "select * from v_default_settings ";
+ $sql .= "order by default_setting_order asc ";
+ $result = $this->database->select($sql, null, 'all');
+ unset($sql, $parameters);
+
+ //unset all settings
+ foreach ($result as $row) {
+ if ($row['default_setting_category'] != 'user') { //skip off-limit categories
+ unset($_SESSION[$row['default_setting_category']][$row['default_setting_subcategory']]);
+ }
+ }
+
+ //set the enabled settings as a session
+ foreach ($result as $row) {
+ if ($row['default_setting_enabled'] == 'true') {
+ $name = $row['default_setting_name'];
+ $category = $row['default_setting_category'];
+ $subcategory = $row['default_setting_subcategory'];
+ if (empty($subcategory)) {
+ if ($name == "array") {
+ $_SESSION[$category][] = $row['default_setting_value'];
+ } else {
+ $_SESSION[$category][$name] = $row['default_setting_value'];
+ }
+ } else {
+ if ($name == "array") {
+ $_SESSION[$category][$subcategory][] = $row['default_setting_value'];
+ } else {
+ $_SESSION[$category][$subcategory]['uuid'] = $row['default_setting_uuid'];
+ $_SESSION[$category][$subcategory][$name] = $row['default_setting_value'];
+ }
+ }
+ }
+ }
+
+ //get the domains settings
+ if (!empty($_SESSION["domain_uuid"]) && is_uuid($_SESSION["domain_uuid"])) {
+
+ //get settings from the database
+ $sql = "select * from v_domain_settings ";
+ $sql .= "where domain_uuid = :domain_uuid ";
+ $sql .= "and domain_setting_enabled = 'true' ";
+ $sql .= " order by domain_setting_order asc ";
+ $parameters['domain_uuid'] = $_SESSION["domain_uuid"];
+ $result = $this->database->select($sql, $parameters, 'all');
+ unset($sql, $parameters);
+
+ //unset the arrays that domains are overriding
+ foreach ($result as $row) {
+ $name = $row['domain_setting_name'];
+ $category = $row['domain_setting_category'];
+ $subcategory = $row['domain_setting_subcategory'];
+ if ($name == "array") {
+ unset($_SESSION[$category][$subcategory]);
}
}
//set the enabled settings as a session
foreach ($result as $row) {
- if ($row['default_setting_enabled'] == 'true') {
- $name = $row['default_setting_name'];
- $category = $row['default_setting_category'];
- $subcategory = $row['default_setting_subcategory'];
- if (empty($subcategory)) {
- if ($name == "array") {
- $_SESSION[$category][] = $row['default_setting_value'];
- }
- else {
- $_SESSION[$category][$name] = $row['default_setting_value'];
- }
- }
- else {
- if ($name == "array") {
- $_SESSION[$category][$subcategory][] = $row['default_setting_value'];
- }
- else {
- $_SESSION[$category][$subcategory]['uuid'] = $row['default_setting_uuid'];
- $_SESSION[$category][$subcategory][$name] = $row['default_setting_value'];
- }
- }
- }
- }
-
- //get the domains settings
- if (!empty($_SESSION["domain_uuid"]) && is_uuid($_SESSION["domain_uuid"])) {
-
- //get settings from the database
- $sql = "select * from v_domain_settings ";
- $sql .= "where domain_uuid = :domain_uuid ";
- $sql .= "and domain_setting_enabled = 'true' ";
- $sql .= " order by domain_setting_order asc ";
- $parameters['domain_uuid'] = $_SESSION["domain_uuid"];
- $result = $this->database->select($sql, $parameters, 'all');
- unset($sql, $parameters);
-
- //unset the arrays that domains are overriding
- foreach ($result as $row) {
+ if ($row['domain_setting_enabled'] == 'true') {
$name = $row['domain_setting_name'];
$category = $row['domain_setting_category'];
$subcategory = $row['domain_setting_subcategory'];
- if ($name == "array") {
- unset($_SESSION[$category][$subcategory]);
- }
- }
-
- //set the enabled settings as a session
- foreach ($result as $row) {
- if ($row['domain_setting_enabled'] == 'true') {
- $name = $row['domain_setting_name'];
- $category = $row['domain_setting_category'];
- $subcategory = $row['domain_setting_subcategory'];
- if (empty($subcategory)) {
- //$$category[$name] = $row['domain_setting_value'];
- if ($name == "array") {
- $_SESSION[$category][] = $row['domain_setting_value'];
- }
- else {
- $_SESSION[$category][$name] = $row['domain_setting_value'];
- }
+ if (empty($subcategory)) {
+ //$$category[$name] = $row['domain_setting_value'];
+ if ($name == "array") {
+ $_SESSION[$category][] = $row['domain_setting_value'];
+ } else {
+ $_SESSION[$category][$name] = $row['domain_setting_value'];
}
- else {
- //$$category[$subcategory][$name] = $row['domain_setting_value'];
- if ($name == "array") {
- $_SESSION[$category][$subcategory][] = $row['domain_setting_value'];
- }
- else {
- $_SESSION[$category][$subcategory][$name] = $row['domain_setting_value'];
- }
+ } else {
+ //$$category[$subcategory][$name] = $row['domain_setting_value'];
+ if ($name == "array") {
+ $_SESSION[$category][$subcategory][] = $row['domain_setting_value'];
+ } else {
+ $_SESSION[$category][$subcategory][$name] = $row['domain_setting_value'];
}
}
}
}
+ }
//get the user settings
- if (array_key_exists("domain_uuid",$_SESSION) && array_key_exists("user_uuid",$_SESSION) && is_uuid($_SESSION["domain_uuid"])) {
- $sql = "select * from v_user_settings ";
- $sql .= "where domain_uuid = :domain_uuid ";
- $sql .= "and user_uuid = :user_uuid ";
- $sql .= " order by user_setting_order asc ";
- $parameters['domain_uuid'] = $_SESSION["domain_uuid"];
- $parameters['user_uuid'] = $_SESSION["user_uuid"];
- $result = $this->database->select($sql, $parameters, 'all');
- if (is_array($result)) {
- foreach ($result as $row) {
- if ($row['user_setting_enabled'] == 'true') {
- $name = $row['user_setting_name'];
- $category = $row['user_setting_category'];
- $subcategory = $row['user_setting_subcategory'];
- if (!empty($row['user_setting_value'])) {
- if (empty($subcategory)) {
- //$$category[$name] = $row['domain_setting_value'];
- if ($name == "array") {
- $_SESSION[$category][] = $row['user_setting_value'];
- }
- else {
- $_SESSION[$category][$name] = $row['user_setting_value'];
- }
+ if (array_key_exists("domain_uuid", $_SESSION) && array_key_exists("user_uuid", $_SESSION) && is_uuid($_SESSION["domain_uuid"])) {
+ $sql = "select * from v_user_settings ";
+ $sql .= "where domain_uuid = :domain_uuid ";
+ $sql .= "and user_uuid = :user_uuid ";
+ $sql .= " order by user_setting_order asc ";
+ $parameters['domain_uuid'] = $_SESSION["domain_uuid"];
+ $parameters['user_uuid'] = $_SESSION["user_uuid"];
+ $result = $this->database->select($sql, $parameters, 'all');
+ if (is_array($result)) {
+ foreach ($result as $row) {
+ if ($row['user_setting_enabled'] == 'true') {
+ $name = $row['user_setting_name'];
+ $category = $row['user_setting_category'];
+ $subcategory = $row['user_setting_subcategory'];
+ if (!empty($row['user_setting_value'])) {
+ if (empty($subcategory)) {
+ //$$category[$name] = $row['domain_setting_value'];
+ if ($name == "array") {
+ $_SESSION[$category][] = $row['user_setting_value'];
+ } else {
+ $_SESSION[$category][$name] = $row['user_setting_value'];
}
- else {
- //$$category[$subcategory][$name] = $row['domain_setting_value'];
- if ($name == "array") {
- $_SESSION[$category][$subcategory][] = $row['user_setting_value'];
- }
- else {
- $_SESSION[$category][$subcategory][$name] = $row['user_setting_value'];
- }
+ } else {
+ //$$category[$subcategory][$name] = $row['domain_setting_value'];
+ if ($name == "array") {
+ $_SESSION[$category][$subcategory][] = $row['user_setting_value'];
+ } else {
+ $_SESSION[$category][$subcategory][$name] = $row['user_setting_value'];
}
}
}
}
}
}
+ }
//set the domain time zone as the default time zone
- date_default_timezone_set($this->settings->get('domain', 'time_zone', date_default_timezone_get()));
+ date_default_timezone_set($this->settings->get('domain', 'time_zone', date_default_timezone_get()));
//set the context
- if (!empty($_SESSION["domain_name"])) {
- $_SESSION["context"] = $_SESSION["domain_name"];
- }
+ if (!empty($_SESSION["domain_name"])) {
+ $_SESSION["context"] = $_SESSION["domain_name"];
+ }
}
/**
- * upgrade application defaults
+ * Initializes a session with domain-specific data.
+ *
+ * This method retrieves a list of all domains from the database and then determines the current domain by checking
+ * the HTTP_HOST server variable. If the username is not set in the session, it will use the first domain in the
+ * list or match the domain name with the given domain name. The relevant domain UUID and name are then stored in
+ * the session.
+ *
+ * @return void
*/
- public function upgrade() {
+ public function session() {
+ //get the list of domains
+ $domains = self::all();
- //add multi-lingual support
- $language = new text;
- $text = $language->get(null, 'core/upgrade');
+ //get the domain
+ $domain_array = explode(":", $_SERVER["HTTP_HOST"] ?? '');
- //includes files
- require dirname(__DIR__, 2) . "/resources/require.php";
-
- //add missing default settings
- $this->settings();
-
- //save the database object to be used by app_defaults.php
- $database = $this->database;
-
- //get the variables
- $config = new config;
- $config_path = $config->config_file;
-
- //get the list of installed apps from the core and app directories (note: GLOB_BRACE doesn't work on some systems)
- $config_list_1 = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_config.php");
- $config_list_2 = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_menu.php");
- $config_list = array_merge((array)$config_list_1, (array)$config_list_2);
- unset($config_list_1,$config_list_2);
- $x=0;
- foreach ($config_list as $config_path) {
- $app_path = dirname($config_path);
- $app_path = preg_replace('/\A.*(\/.*\/.*)\z/', '$1', $app_path);
- include($config_path);
- $x++;
- }
-
- //get the domains
- $sql = "select * from v_domains ";
- $domains = $this->database->select($sql, null, 'all');
- unset($sql);
-
- //get the list of installed apps from the core and mod directories
- $default_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_defaults.php");
-
- //loop through all domains
- $domains_processed = 1;
- foreach ($domains as $domain) {
- //get the values from database and set them as php variables
- $domain_uuid = $domain["domain_uuid"];
- $domain_name = $domain["domain_name"];
-
- //get the context
- $context = $domain_name;
-
- //get the email queue settings
- $settings = new settings(["database" => $this->database, "domain_uuid" => $domain_uuid]);
-
- //run the php code in app_defaults.php
- foreach ($default_list as $default_path) {
- include($default_path);
- }
-
- //track the number of domains processed
- $domains_processed++;
- }
-
- } //end upgrade method
-
- /**
- * add missing default settings
- * update the uuid for older default settings that were added before the uuids was predefined.
- */
- public function settings() {
-
- //includes files
- require dirname(__DIR__, 2) . "/resources/require.php";
-
- //get an array of the default settings UUIDs
- $sql = "select * from v_default_settings ";
- $result = $this->database->select($sql, null, 'all');
- foreach($result as $row) {
- $setting[$row['default_setting_uuid']] = 1;
- }
- unset($sql);
-
- //get the list of default settings
- $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
- $x=0;
- foreach ($config_list as $config_path) {
- include($config_path);
- $x++;
- }
- $x = 0;
- foreach ($apps as $app) {
- if (isset($app['default_settings']) && is_array($app['default_settings'])) {
- foreach ($app['default_settings'] as $row) {
- if (!isset($setting[$row['default_setting_uuid']])) {
- $array['default_settings'][$x] = $row;
- $array['default_settings'][$x]['app_uuid'] = $app['uuid'];
- $x++;
- }
+ //set domain_name and domain_uuid and update domains array with domain_uuid as the key
+ foreach ($domains as $row) {
+ if (!isset($_SESSION['username'])) {
+ if (!empty($domains) && count($domains) == 1) {
+ $_SESSION["domain_uuid"] = $row["domain_uuid"];
+ $_SESSION["domain_name"] = $row['domain_name'];
+ } else {
+ if ($row['domain_name'] == $domain_array[0] || $row['domain_name'] == 'www.' . $domain_array[0]) {
+ $_SESSION["domain_uuid"] = $row["domain_uuid"];
+ $_SESSION["domain_name"] = $row["domain_name"];
}
}
}
+ }
- //add the missing default settings
- if (isset($array) && is_array($array) && count($array) > 0) {
- //grant temporary permissions
- $p = permissions::new();
- $p->add('default_setting_add', 'temp');
-
- //execute insert
- $this->database->app_name = 'default_settings';
- $this->database->app_uuid = '2c2453c0-1bea-4475-9f44-4d969650de09';
- $this->database->save($array, false);
- unset($array);
-
- //revoke temporary permissions
- $p->delete('default_setting_add', 'temp');
- }
-
- } //end settings method
-
- /**
- * get all enabled domains
- * @returns array enabled domains with uuid as array key
- */
- public static function enabled() {
-
- //define database as global
- global $database;
-
- //define default return value
- $domains = [];
-
- //get the domains from the database
- $sql = "select * from v_domains ";
- $sql .= "where domain_enabled = true ";
- $sql .= "order by domain_name asc; ";
- $result = $database->select($sql, null, 'all');
- if (!empty($result)) {
- foreach($result as $row) {
- $domains[$row['domain_uuid']] = $row;
- }
- }
-
- //return the domains array
- return $domains;
+ //set the domains session array
+ $_SESSION['domains'] = $domains;
}
/**
- * get all disabled domains
- * @returns array disabled domains with uuid as array key
- */
- public static function disabled() {
-
- //define database as global
- global $database;
-
- //define default return value
- $domains = [];
-
- //get the domains from the database
- $sql = "select * from v_domains ";
- $sql .= "where domain_enabled = false ";
- $sql .= "order by domain_name asc; ";
- $result = $database->select($sql, null, 'all');
- if (!empty($result)) {
- foreach($result as $row) {
- $domains[$row['domain_uuid']] = $row;
- }
- }
-
- //return the domains array
- return $domains;
- }
-
- /**
- * get all domains
- * @returns array all domains with uuid as array key
+ * Retrieves a list of all domains from the database.
+ *
+ * @return array An array of domain data, where each key is a unique domain UUID and each value is an associative
+ * array containing the domain's details.
*/
public static function all() {
//define database as global
- global $database;
+ global $database;
//define default return value
- $domains = [];
+ $domains = [];
//get the domains from the database
- $sql = "select * from v_domains ";
- $sql .= "order by domain_name asc; ";
- $result = $database->select($sql, null, 'all');
- if (!empty($result)) {
- foreach($result as $row) {
- $domains[$row['domain_uuid']] = $row;
- }
+ $sql = "select * from v_domains ";
+ $sql .= "order by domain_name asc; ";
+ $result = $database->select($sql, null, 'all');
+ if (!empty($result)) {
+ foreach ($result as $row) {
+ $domains[$row['domain_uuid']] = $row;
}
+ }
//return the domains array
- return $domains;
- }
-
- /**
- * get a domain list
- * @returns void
- */
- public function session() {
- //get the list of domains
- $domains = self::all();
-
- //get the domain
- $domain_array = explode(":", $_SERVER["HTTP_HOST"] ?? '');
-
- //set domain_name and domain_uuid and update domains array with domain_uuid as the key
- foreach($domains as $row) {
- if (!isset($_SESSION['username'])) {
- if (!empty($domains) && count($domains) == 1) {
- $_SESSION["domain_uuid"] = $row["domain_uuid"];
- $_SESSION["domain_name"] = $row['domain_name'];
- }
- else {
- if ($row['domain_name'] == $domain_array[0] || $row['domain_name'] == 'www.'.$domain_array[0]) {
- $_SESSION["domain_uuid"] = $row["domain_uuid"];
- $_SESSION["domain_name"] = $row["domain_name"];
- }
- }
- }
- }
-
- //set the domains session array
- $_SESSION['domains'] = $domains;
+ return $domains;
}
}
diff --git a/resources/classes/email.php b/resources/classes/email.php
index 008d257d9d..278c0eea4b 100644
--- a/resources/classes/email.php
+++ b/resources/classes/email.php
@@ -28,613 +28,627 @@
* email class
*
*/
- class email {
+class email {
- /**
- * declare constant variables
- */
- const app_name = 'email';
- const app_uuid = '7a4fef67-5bf8-436a-ae25-7e3c03afcf96';
+ /**
+ * declare constant variables
+ */
+ const app_name = 'email';
+ const app_uuid = '7a4fef67-5bf8-436a-ae25-7e3c03afcf96';
- /**
- * 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;
- /**
- * declare public variables
- */
- public $method;
- public $recipients;
- public $subject;
- public $body;
- public $from_address;
- public $from_name;
- public $priority;
- public $debug_level;
- public $attachments;
- public $read_confirmation;
- public $error;
- public $response;
- public $headers;
- public $content_type;
- public $reply_to;
- public $date;
+ /**
+ * declare public variables
+ */
+ public $method;
+ public $recipients;
+ public $subject;
+ public $body;
+ public $from_address;
+ public $from_name;
+ public $priority;
+ public $debug_level;
+ public $attachments;
+ public $read_confirmation;
+ public $error;
+ public $response;
+ public $headers;
+ public $content_type;
+ public $reply_to;
+ public $date;
- /**
- * 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;
- /**
- * User 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 $user_uuid;
+ /**
+ * User 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 $user_uuid;
- /**
- * declare private variables
- */
- private $name;
+ /**
+ * declare private variables
+ *
+ * @var string $name Property is only written but never read
+ */
+ private $name;
- /**
- * called when the object is created
- */
- public function __construct(array $setting_array = []) {
- //assign the variables
- $this->name = 'email';
- $this->priority = 0;
- $this->debug_level = 3;
- $this->read_confirmation = false;
+ /**
+ * called when the object is created
+ */
+ public function __construct(array $setting_array = []) {
+ //assign the variables
+ $this->name = 'email'; //unused
+ $this->priority = 0;
+ $this->debug_level = 3;
+ $this->read_confirmation = false;
- //set the domain and user uuids
- $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
- $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? '';
+ //set the domain and user uuids
+ $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
+ $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? '';
- //set the objects
- $this->database = $setting_array['database'] ?? database::new();
- $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
+ //set the objects
+ $this->database = $setting_array['database'] ?? database::new();
+ $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
+ }
+
+ /**
+ * Parse an email message.
+ *
+ * This method takes a raw email message as input and parses it into its constituent parts,
+ * including headers, body, attachments, and other metadata. The parsed data is stored in
+ * various properties of the object, making it available for further processing or storage.
+ *
+ * @param string $message Raw email message to be parsed.
+ */
+ public function parse($message) {
+ //includes
+ require_once('resources/pop3/mime_parser.php');
+ require_once('resources/pop3/rfc822_addresses.php');
+ if (file_exists($_SERVER["PROJECT_ROOT"] . "/app/emails/email_transcription.php")) {
+ require_once($_SERVER["PROJECT_ROOT"] . "/app/emails/email_transcription.php");
}
- /**
- * parse raw emails
- */
- public function parse($message) {
- //includes
- require_once('resources/pop3/mime_parser.php');
- require_once('resources/pop3/rfc822_addresses.php');
- if (file_exists($_SERVER["PROJECT_ROOT"]."/app/emails/email_transcription.php")) {
- require_once($_SERVER["PROJECT_ROOT"]."/app/emails/email_transcription.php");
- }
+ //parse the email message
+ $mime = new mime_parser_class;
+ $mime->decode_bodies = 1;
+ $parameters = [
+ //'File'=>$message_file,
- //parse the email message
- $mime = new mime_parser_class;
- $mime->decode_bodies = 1;
- $parameters = array(
- //'File'=>$message_file,
+ // Read a message from a string instead of a file
+ 'Data' => $message,
- // Read a message from a string instead of a file
- 'Data' => $message,
+ // Save the message body parts to a directory
+ // 'SaveBody' => '/tmp',
- // Save the message body parts to a directory
- // 'SaveBody' => '/tmp',
+ // Do not retrieve or save message body parts
+ // 'SkipBody' => 1,
+ ];
+ $success = $mime->Decode($parameters, $decoded);
+ unset($parameters);
- // Do not retrieve or save message body parts
- // 'SkipBody' => 1,
- );
- $success = $mime->Decode($parameters, $decoded);
- unset($parameters);
+ if (!$success) {
+ echo "MIME message decoding error: " . HtmlSpecialChars($mime->error) . "\n";
+ } else {
- if (!$success) {
- echo "MIME message decoding error: ".HtmlSpecialChars($mime->error)."\n";
- }
- else {
+ //get the headers
+ $this->headers = json_decode($decoded[0]["Headers"]["x-headers:"], true);
+ $this->subject = $decoded[0]["Headers"]["subject:"];
+ $this->from_name = $decoded[0]["ExtractedAddresses"]["from:"][0]["name"];
+ $this->from_address = $decoded[0]["ExtractedAddresses"]["from:"][0]["address"];
+ $this->reply_to = $decoded[0]["Headers"]["reply-to:"];
+ $this->recipients = $decoded[0]["ExtractedAddresses"]["to:"];
+ $this->date = $decoded[0]["Headers"]["date:"];
- //get the headers
- $this->headers = json_decode($decoded[0]["Headers"]["x-headers:"], true);
- $this->subject = $decoded[0]["Headers"]["subject:"];
- $this->from_name = $decoded[0]["ExtractedAddresses"]["from:"][0]["name"];
- $this->from_address = $decoded[0]["ExtractedAddresses"]["from:"][0]["address"];
- $this->reply_to = $decoded[0]["Headers"]["reply-to:"];
- $this->recipients = $decoded[0]["ExtractedAddresses"]["to:"];
- $this->date = $decoded[0]["Headers"]["date:"];
+ //debug information
+ //view_array($decoded[0]);
+ //view_array($this);
+ //view_array($this->recipients);
- //debug information
- //view_array($decoded[0]);
- //view_array($this);
- //view_array($this->recipients);
+ //get the body
+ $this->body = ''; //$parts_array["Parts"][0]["Headers"]["content-type:"];
- //get the body
- $this->body = ''; //$parts_array["Parts"][0]["Headers"]["content-type:"];
-
- //get the body
- $this->body = '';
- $this->content_type = $decoded[0]['Headers']['content-type:'];
- if (substr($this->content_type, 0, 15) == "multipart/mixed" || substr($this->content_type, 0, 21) == "multipart/alternative") {
- foreach ($decoded[0]["Parts"] as $row) {
- $body_content_type = $row["Headers"]["content-type:"];
- if (substr($body_content_type, 0, 9) == "text/html") {
- $this->body = $row["Body"];
- }
- if (substr($body_content_type, 0, 10) == "text/plain") {
- $body_plain = $row["Body"];
- $this->body = $body_plain;
- }
+ //get the body
+ $this->body = '';
+ $this->content_type = $decoded[0]['Headers']['content-type:'];
+ if (substr($this->content_type, 0, 15) == "multipart/mixed" || substr($this->content_type, 0, 21) == "multipart/alternative") {
+ foreach ($decoded[0]["Parts"] as $row) {
+ $body_content_type = $row["Headers"]["content-type:"];
+ if (substr($body_content_type, 0, 9) == "text/html") {
+ $this->body = $row["Body"];
+ }
+ if (substr($body_content_type, 0, 10) == "text/plain") {
+ $body_plain = $row["Body"];
+ $this->body = $body_plain;
}
}
- else {
- $content_type_array = explode(";", $content_type);
- $this->body = $decoded[0]["Body"];
- //if ($content_type_array[0] == "text/html" || $content_type_array[0] == "text/plain") {
- // $body = $row["Body"];
- //}
- }
+ } else {
+ $content_type_array = explode(";", $content_type);
+ $this->body = $decoded[0]["Body"];
+ //if ($content_type_array[0] == "text/html" || $content_type_array[0] == "text/plain") {
+ // $body = $row["Body"];
+ //}
+ }
- //get the attachments and add to the email
- $x = 0;
- foreach ($decoded[0]["Parts"] as $parts_array) {
- //image/tiff;name="testfax.tif"
- //text/plain; charset=ISO-8859-1; format=flowed
- $content_type = $parts_array["Parts"][0]["Headers"]["content-type:"];
+ //get the attachments and add to the email
+ $x = 0;
+ foreach ($decoded[0]["Parts"] as $parts_array) {
+ //image/tiff;name="testfax.tif"
+ //text/plain; charset=ISO-8859-1; format=flowed
+ $content_type = $parts_array["Parts"][0]["Headers"]["content-type:"];
- //base64, 7bit
- $content_transfer_encoding = $parts_array["Parts"][0]["Headers"]["content-transfer-encoding:"];
+ //base64, 7bit
+ $content_transfer_encoding = $parts_array["Parts"][0]["Headers"]["content-transfer-encoding:"];
- //inline;filename="testfax.tif"
- $content_disposition = $parts_array["Parts"][0]["Headers"]["content-disposition"];
+ //inline;filename="testfax.tif"
+ $content_disposition = $parts_array["Parts"][0]["Headers"]["content-disposition"];
- //testfax.tif
- $file = $parts_array["FileName"];
+ //testfax.tif
+ $file = $parts_array["FileName"];
- //inline
- $filedisposition = $parts_array["FileDisposition"];
+ //inline
+ $filedisposition = $parts_array["FileDisposition"];
- $body_part = $parts_array["BodyPart"];
- $body_length = $parts_array["BodyLength"];
+ $body_part = $parts_array["BodyPart"];
+ $body_length = $parts_array["BodyLength"];
- if (!empty($file)) {
- //get the file information
- $file_ext = pathinfo($file, PATHINFO_EXTENSION);
- $file_name = substr($file, 0, (strlen($file) - strlen($file_ext))-1 );
- $encoding = "base64"; //base64_decode
+ if (!empty($file)) {
+ //get the file information
+ $file_ext = pathinfo($file, PATHINFO_EXTENSION);
+ $file_name = substr($file, 0, (strlen($file) - strlen($file_ext)) - 1);
+ $encoding = "base64"; //base64_decode
- switch ($file_ext){
- case "wav":
- $mime_type = "audio/x-wav";
- break;
- case "mp3":
- $mime_type = "audio/x-mp3";
- break;
- case "pdf":
- $mime_type = "application/pdf";
- break;
- case "tif":
- $mime_type = "image/tiff";
- break;
- case "tiff":
- $mime_type = "image/tiff";
- break;
- default:
- $mime_type = "binary/octet-stream";
- break;
- }
-
- //add attachment(s)
- $this->attachments[$x]['type'] = 'string';
- $this->attachments[$x]['name'] = $file;
- $this->attachments[$x]['value'] = $parts_array["Body"];
-
- //increment the id
- $x++;
+ switch ($file_ext) {
+ case "wav":
+ $mime_type = "audio/x-wav";
+ break;
+ case "mp3":
+ $mime_type = "audio/x-mp3";
+ break;
+ case "pdf":
+ $mime_type = "application/pdf";
+ break;
+ case "tif":
+ $mime_type = "image/tiff";
+ break;
+ case "tiff":
+ $mime_type = "image/tiff";
+ break;
+ default:
+ $mime_type = "binary/octet-stream";
+ break;
}
- }
+ //add attachment(s)
+ $this->attachments[$x]['type'] = 'string';
+ $this->attachments[$x]['name'] = $file;
+ $this->attachments[$x]['value'] = $parts_array["Body"];
+
+ //increment the id
+ $x++;
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Sends an email.
+ *
+ * This method determines whether to use a queue or send directly based on email_queue.enabled setting.
+ * If using a queue, it prepares and adds the email to the queue. If sending directly,
+ * it uses PHPMailer to send the email.
+ *
+ * @return string A human-readable response for debugging.
+ */
+ public function send() {
+
+ //set the send_method if not already set
+ if (!isset($this->method)) {
+ if ($this->settings->get('email_queue', 'enabled', true)) {
+ $this->method = 'queue';
+ } else {
+ $this->method = 'direct';
}
}
- /**
- * send emails
- */
- public function send() {
+ //add the email to the queue
+ if ($this->method == 'queue') {
- //set the send_method if not already set
- if (!isset($this->method)) {
- if ($this->settings->get('email_queue','enabled', true)) {
- $this->method = 'queue';
- }
- else {
- $this->method = 'direct';
+ //add the email_queue_uuid
+ $email_queue_uuid = uuid();
+
+ //set the email from address and name
+ $email_from = $this->from_address;
+ if (!empty($this->from_name)) {
+ $email_from = $this->from_name . '<' . $email_from . '>';
+ }
+
+ //prepare the array
+ $array['email_queue'][0]['email_queue_uuid'] = $email_queue_uuid;
+ $array['email_queue'][0]['domain_uuid'] = $this->domain_uuid;
+ $array['email_queue'][0]['hostname'] = gethostname();
+ $array['email_queue'][0]['email_date'] = 'now()';
+ $array['email_queue'][0]['email_from'] = $email_from;
+ $array['email_queue'][0]['email_to'] = $this->recipients;
+ $array['email_queue'][0]['email_subject'] = $this->subject;
+ $array['email_queue'][0]['email_body'] = $this->body;
+ $array['email_queue'][0]['email_status'] = 'waiting';
+ $array['email_queue'][0]['email_retry_count'] = null;
+ //$array['email_queue'][0]['email_action_before'] = $email_action_before;
+ //$array['email_queue'][0]['email_action_after'] = $email_action_after;
+
+ //add email attachments
+ if (is_array($this->attachments) && sizeof($this->attachments) > 0) {
+ $y = 0;
+ foreach ($this->attachments as $attachment) {
+ //set the name of the file, determine extension
+ if ($attachment['path'] && $attachment['name']) {
+ if (file_exists($attachment['path'] && $attachment['name'])) {
+ $attachment['type'] = strtolower(pathinfo($attachment['name'], PATHINFO_EXTENSION));
+ }
+ } elseif ($attachment['value']) {
+ //old method
+ if (strlen($attachment['value']) < 255 && file_exists($attachment['value'])) {
+ $attachment['name'] = $attachment['name'] != '' ? $attachment['name'] : basename($attachment['value']);
+ $attachment['path'] = pathinfo($attachment['value'], PATHINFO_DIRNAME);
+ $attachment['type'] = strtolower(pathinfo($attachment['value'], PATHINFO_EXTENSION));
+ }
+ }
+
+ //set the mime type
+ switch ($attachment['type']) {
+ case "jpg":
+ case "jpeg":
+ $attachment['mime_type'] = 'image/jpeg';
+ break;
+ case "gif":
+ $attachment['mime_type'] = 'image/gif';
+ break;
+ case "png":
+ $attachment['mime_type'] = 'image/png';
+ break;
+ case "pdf":
+ $attachment['mime_type'] = 'application/pdf';
+ break;
+ case "tif":
+ case "tiff":
+ $attachment['mime_type'] = 'image/tiff';
+ break;
+ case "mp3":
+ $attachment['mime_type'] = 'audio/mpeg';
+ break;
+ case "wav":
+ $attachment['mime_type'] = 'audio/x-wav';
+ break;
+ case "opus":
+ $attachment['mime_type'] = 'audio/opus';
+ break;
+ case "ogg":
+ $attachment['mime_type'] = 'audio/ogg';
+ break;
+ default:
+ $attachment['mime_type'] = 'binary/octet-stream';
+ }
+
+ //add the attachments to the array
+ $array['email_queue_attachments'][$y]['email_queue_attachment_uuid'] = uuid();
+ $array['email_queue_attachments'][$y]['email_queue_uuid'] = $email_queue_uuid;
+ $array['email_queue_attachments'][$y]['domain_uuid'] = $this->domain_uuid;
+ $array['email_queue_attachments'][$y]['email_attachment_mime_type'] = $attachment['mime_type'];
+ $array['email_queue_attachments'][$y]['email_attachment_type'] = $attachment['type'];
+ $array['email_queue_attachments'][$y]['email_attachment_name'] = $attachment['name'];
+ $array['email_queue_attachments'][$y]['email_attachment_path'] = $attachment['path'];
+ $array['email_queue_attachments'][$y]['email_attachment_base64'] = $attachment['base64'];
+ $y++;
}
}
- //add the email to the queue
- if ($this->method == 'queue') {
+ //add temporary permissions
+ $p = permissions::new();
+ $p->add("email_queue_add", 'temp');
+ $p->add("email_queue_attachment_add", 'temp');
- //add the email_queue_uuid
- $email_queue_uuid = uuid();
+ //save the dialplan
+ $this->database->app_name = 'email';
+ $this->database->app_uuid = 'e24b5dab-3bcc-42e8-99c1-19b0c558c2d7';
+ $this->database->save($array);
+ //$dialplan_response = $this->database->message;
+ unset($array);
- //set the email from address and name
- $email_from = $this->from_address;
- if (!empty($this->from_name)) {
- $email_from = $this->from_name.'<'.$email_from.'>';
+ //remove temporary permissions
+ $p->delete("dialplan_add", 'temp');
+ $p->delete("dialplan_detail_add", 'temp');
+
+ //return a human readable response for debugging
+ if ($this->database->message['message'] == 'OK') {
+ return "Added to queue";
+ } else {
+ //return the SQL server message
+ return $this->database->message['message'];
+ }
+ }
+
+ //send the email directly
+ if ($this->method == 'direct') {
+ /*
+ RECIPIENTS NOTE:
+
+ Pass in a single email address...
+
+ user@domain.com
+
+ Pass in a comma or semi-colon delimited string of e-mail addresses...
+
+ user@domain.com,user2@domain2.com,user3@domain3.com
+ user@domain.com;user2@domain2.com;user3@domain3.com
+
+ Pass in a simple array of email addresses...
+
+ Array (
+ [0] => user@domain.com
+ [1] => user2@domain2.com
+ [2] => user3@domain3.com
+ )
+
+ Pass in a multi-dimentional array of addresses (delivery, address, name)...
+
+ Array (
+ [0] => Array (
+ [delivery] => to
+ [address] => user@domain.com
+ [name] => user 1
+ )
+ [1] => Array (
+ [delivery] => cc
+ [address] => user2@domain2.com
+ [name] => user 2
+ )
+ [2] => Array (
+ [delivery] => bcc
+ [address] => user3@domain3.com
+ [name] => user 3
+ )
+ )
+
+ ATTACHMENTS NOTE:
+
+ Pass in as many files as necessary in an array in the following format...
+
+ Array (
+ [0] => Array (
+ [mime_type] => image/jpeg (will be determined by file extension, if empty)
+ [name] => filename.ext
+ [path] => /source/folder/ (not used if base64 content)
+ [base64] => file content as base64 (not used if name and path set)
+ [cid] => content id of file attachment (only used if referencing attached files in body content)
+ )
+ [1] => Array (
+ ...
+ )
+ )
+
+ ERROR RESPONSE:
+
+ Error messages are stored in the variable passed into $this->error BY REFERENCE
+ */
+
+ try {
+ //include the phpmailer classes
+ include_once("resources/phpmailer/class.phpmailer.php");
+ include_once("resources/phpmailer/class.smtp.php");
+
+ //use the email default settings
+ if (!empty($this->settings->get('email', 'smtp_hostname'))) {
+ $smtp['hostname'] = $this->settings->get('email', 'smtp_hostname');
}
+ $smtp['host'] = $this->settings->get('email', 'smtp_host', '127.0.0.1');
+ $smtp['port'] = (int)$this->settings->get('email', 'smtp_port', 0);
+ $smtp['secure'] = $this->settings->get('email', 'smtp_secure');
+ $smtp['auth'] = $this->settings->get('email', 'smtp_auth');
+ $smtp['username'] = $this->settings->get('email', 'smtp_username');
+ $smtp['password'] = $this->settings->get('email', 'smtp_password');
+ $smtp['from'] = $this->settings->get('voicemail', 'smtp_from') ?? $this->settings->get('email', 'smtp_from');
+ $smtp['from_name'] = $this->settings->get('voicemail', 'smtp_from_name') ?? $this->settings->get('email', 'smtp_from_name');
+ $smtp['validate_certificate'] = $this->settings->get('email', 'smtp_validate_certificate', true);
+ $smtp['crypto_method'] = $this->settings->get('email', 'smtp_crypto_method') ?? null;
- //prepare the array
- $array['email_queue'][0]['email_queue_uuid'] = $email_queue_uuid;
- $array['email_queue'][0]['domain_uuid'] = $this->domain_uuid;
- $array['email_queue'][0]['hostname'] = gethostname();
- $array['email_queue'][0]['email_date'] = 'now()';
- $array['email_queue'][0]['email_from'] = $email_from;
- $array['email_queue'][0]['email_to'] = $this->recipients;
- $array['email_queue'][0]['email_subject'] = $this->subject;
- $array['email_queue'][0]['email_body'] = $this->body;
- $array['email_queue'][0]['email_status'] = 'waiting';
- $array['email_queue'][0]['email_retry_count'] = null;
- //$array['email_queue'][0]['email_action_before'] = $email_action_before;
- //$array['email_queue'][0]['email_action_after'] = $email_action_after;
-
- //add email attachments
- if (is_array($this->attachments) && sizeof($this->attachments) > 0) {
- $y = 0;
- foreach ($this->attachments as $attachment) {
- //set the name of the file, determine extension
- if ($attachment['path'] && $attachment['name']) {
- if (file_exists($attachment['path'] && $attachment['name'])) {
- $attachment['type'] = strtolower(pathinfo($attachment['name'], PATHINFO_EXTENSION));
- }
+ //override the domain-specific smtp server settings, if any
+ $sql = "select domain_setting_subcategory, domain_setting_value ";
+ $sql .= "from v_domain_settings ";
+ $sql .= "where domain_uuid = :domain_uuid ";
+ $sql .= "and (domain_setting_category = 'email' or domain_setting_category = 'voicemail') ";
+ $sql .= "and domain_setting_enabled = 'true' ";
+ $parameters['domain_uuid'] = $this->domain_uuid;
+ $result = $this->database->select($sql, $parameters, 'all');
+ if (is_array($result) && @sizeof($result) != 0) {
+ foreach ($result as $row) {
+ if ($row['domain_setting_value'] != '') {
+ $smtp[str_replace('smtp_', '', $row["domain_setting_subcategory"])] = $row['domain_setting_value'];
}
- else if ($attachment['value']) {
- //old method
- if (strlen($attachment['value']) < 255 && file_exists($attachment['value'])) {
- $attachment['name'] = $attachment['name'] != '' ? $attachment['name'] : basename($attachment['value']);
- $attachment['path'] = pathinfo($attachment['value'], PATHINFO_DIRNAME);
- $attachment['type'] = strtolower(pathinfo($attachment['value'], PATHINFO_EXTENSION));
- }
- }
-
- //set the mime type
- switch ($attachment['type']) {
- case "jpg":
- case "jpeg":
- $attachment['mime_type'] = 'image/jpeg';
- break;
- case "gif":
- $attachment['mime_type'] = 'image/gif';
- break;
- case "png":
- $attachment['mime_type'] = 'image/png';
- break;
- case "pdf":
- $attachment['mime_type'] = 'application/pdf';
- break;
- case "tif":
- case "tiff":
- $attachment['mime_type'] = 'image/tiff';
- break;
- case "mp3":
- $attachment['mime_type'] = 'audio/mpeg';
- break;
- case "wav":
- $attachment['mime_type'] = 'audio/x-wav';
- break;
- case "opus":
- $attachment['mime_type'] = 'audio/opus';
- break;
- case "ogg":
- $attachment['mime_type'] = 'audio/ogg';
- break;
- default:
- $attachment['mime_type'] = 'binary/octet-stream';
- }
-
- //add the attachments to the array
- $array['email_queue_attachments'][$y]['email_queue_attachment_uuid'] = uuid();
- $array['email_queue_attachments'][$y]['email_queue_uuid'] = $email_queue_uuid;
- $array['email_queue_attachments'][$y]['domain_uuid'] = $this->domain_uuid;
- $array['email_queue_attachments'][$y]['email_attachment_mime_type'] = $attachment['mime_type'];
- $array['email_queue_attachments'][$y]['email_attachment_type'] = $attachment['type'];
- $array['email_queue_attachments'][$y]['email_attachment_name'] = $attachment['name'];
- $array['email_queue_attachments'][$y]['email_attachment_path'] = $attachment['path'];
- $array['email_queue_attachments'][$y]['email_attachment_base64'] = $attachment['base64'];
- $y++;
}
}
+ unset($sql, $parameters, $result, $row);
- //add temporary permissions
- $p = permissions::new();
- $p->add("email_queue_add", 'temp');
- $p->add("email_queue_attachment_add", 'temp');
+ //value adjustments
+ $smtp['auth'] = ($smtp['auth'] == "true") ? true : false;
+ $smtp['password'] = ($smtp['password'] != '') ? $smtp['password'] : null;
+ $smtp['secure'] = ($smtp['secure'] != "none") ? $smtp['secure'] : null;
+ $smtp['username'] = ($smtp['username'] != '') ? $smtp['username'] : null;
- //save the dialplan
- $this->database->app_name = 'email';
- $this->database->app_uuid = 'e24b5dab-3bcc-42e8-99c1-19b0c558c2d7';
- $this->database->save($array);
- //$dialplan_response = $this->database->message;
- unset($array);
+ //create the email object and set general settings
+ $mail = new PHPMailer();
+ $mail->IsSMTP();
+ if (!empty($smtp['hostname'])) {
+ $mail->Hostname = $smtp['hostname'];
+ }
+ $mail->Host = $smtp['host'];
+ if (is_numeric($smtp['port'])) {
+ $mail->Port = $smtp['port'];
+ }
- //remove temporary permissions
- $p->delete("dialplan_add", 'temp');
- $p->delete("dialplan_detail_add", 'temp');
-
- //return a human readable response for debugging
- if ($this->database->message['message'] == 'OK') {
- return "Added to queue";
+ if ($smtp['auth'] == "true") {
+ $mail->SMTPAuth = true;
+ $mail->Username = $smtp['username'];
+ $mail->Password = $smtp['password'];
} else {
- //return the SQL server message
- return $this->database->message['message'];
+ $mail->SMTPAuth = false;
}
- }
- //send the email directly
- if ($this->method == 'direct') {
- /*
- RECIPIENTS NOTE:
+ $smtp_secure = true;
+ if ($smtp['secure'] == "") {
+ $mail->SMTPSecure = 'none';
+ $mail->SMTPAutoTLS = false;
+ $smtp_secure = false;
+ } elseif ($smtp['secure'] == "none") {
+ $mail->SMTPSecure = 'none';
+ $mail->SMTPAutoTLS = false;
+ $smtp_secure = false;
+ } else {
+ $mail->SMTPSecure = $smtp['secure'];
+ }
- Pass in a single email address...
+ if ($smtp_secure && isset($smtp['validate_certificate']) && !$smtp['validate_certificate']) {
+ //bypass certificate check e.g. for self-signed certificates
+ $smtp_options['ssl']['verify_peer'] = false;
+ $smtp_options['ssl']['verify_peer_name'] = false;
+ $smtp_options['ssl']['allow_self_signed'] = true;
+ }
- user@domain.com
+ //used to set the SSL version
+ if ($smtp_secure && isset($smtp['crypto_method'])) {
+ $smtp_options['ssl']['crypto_method'] = $smtp['crypto_method'];
+ }
- Pass in a comma or semi-colon delimited string of e-mail addresses...
+ //add SMTP Options if the array exists
+ if (is_array($smtp_options)) {
+ $mail->SMTPOptions = $smtp_options;
+ }
- user@domain.com,user2@domain2.com,user3@domain3.com
- user@domain.com;user2@domain2.com;user3@domain3.com
+ $this->from_address = ($this->from_address != '') ? $this->from_address : $smtp['from'];
+ $this->from_name = ($this->from_name != '') ? $this->from_name : $smtp['from_name'];
+ $mail->SetFrom($this->from_address, $this->from_name);
+ $mail->AddReplyTo($this->from_address, $this->from_name);
+ $mail->Subject = $this->subject;
+ $mail->MsgHTML($this->body);
+ $mail->Priority = $this->priority;
+ if ($this->read_confirmation) {
+ $mail->AddCustomHeader('X-Confirm-Reading-To: ' . $this->from_address);
+ $mail->AddCustomHeader('Return-Receipt-To: ' . $this->from_address);
+ $mail->AddCustomHeader('Disposition-Notification-To: ' . $this->from_address);
+ }
+ if (is_numeric($this->debug_level) && $this->debug_level > 0) {
+ $mail->SMTPDebug = $this->debug_level;
+ }
+ $mail->Timeout = 20; //set the timeout (seconds)
+ $mail->SMTPKeepAlive = true; //don't close the connection between messages
- Pass in a simple array of email addresses...
+ //add the email recipients
+ $address_found = false;
+ if (!is_array($this->recipients)) { // must be a single or delimited recipient address(s)
+ $this->recipients = str_replace(' ', '', $this->recipients);
+ $this->recipients = str_replace(',', ';', $this->recipients);
+ $this->recipients = explode(';', $this->recipients); // convert to array of addresses
+ }
- Array (
- [0] => user@domain.com
- [1] => user2@domain2.com
- [2] => user3@domain3.com
- )
-
- Pass in a multi-dimentional array of addresses (delivery, address, name)...
-
- Array (
- [0] => Array (
- [delivery] => to
- [address] => user@domain.com
- [name] => user 1
- )
- [1] => Array (
- [delivery] => cc
- [address] => user2@domain2.com
- [name] => user 2
- )
- [2] => Array (
- [delivery] => bcc
- [address] => user3@domain3.com
- [name] => user 3
- )
- )
-
- ATTACHMENTS NOTE:
-
- Pass in as many files as necessary in an array in the following format...
-
- Array (
- [0] => Array (
- [mime_type] => image/jpeg (will be determined by file extension, if empty)
- [name] => filename.ext
- [path] => /source/folder/ (not used if base64 content)
- [base64] => file content as base64 (not used if name and path set)
- [cid] => content id of file attachment (only used if referencing attached files in body content)
- )
- [1] => Array (
- ...
- )
- )
-
- ERROR RESPONSE:
-
- Error messages are stored in the variable passed into $this->error BY REFERENCE
- */
-
- try {
- //include the phpmailer classes
- include_once("resources/phpmailer/class.phpmailer.php");
- include_once("resources/phpmailer/class.smtp.php");
-
- //use the email default settings
- if (!empty($this->settings->get('email','smtp_hostname'))) {
- $smtp['hostname'] = $this->settings->get('email','smtp_hostname');
- }
- $smtp['host'] = $this->settings->get('email','smtp_host', '127.0.0.1');
- $smtp['port'] = (int)$this->settings->get('email','smtp_port', 0);
- $smtp['secure'] = $this->settings->get('email','smtp_secure');
- $smtp['auth'] = $this->settings->get('email','smtp_auth');
- $smtp['username'] = $this->settings->get('email','smtp_username');
- $smtp['password'] = $this->settings->get('email','smtp_password');
- $smtp['from'] = $this->settings->get('voicemail','smtp_from') ?? $this->settings->get('email','smtp_from');
- $smtp['from_name'] = $this->settings->get('voicemail','smtp_from_name') ?? $this->settings->get('email','smtp_from_name');
- $smtp['validate_certificate'] = $this->settings->get('email','smtp_validate_certificate', true);
- $smtp['crypto_method'] = $this->settings->get('email','smtp_crypto_method') ?? null;
-
- //override the domain-specific smtp server settings, if any
- $sql = "select domain_setting_subcategory, domain_setting_value ";
- $sql .= "from v_domain_settings ";
- $sql .= "where domain_uuid = :domain_uuid ";
- $sql .= "and (domain_setting_category = 'email' or domain_setting_category = 'voicemail') ";
- $sql .= "and domain_setting_enabled = 'true' ";
- $parameters['domain_uuid'] = $this->domain_uuid;
- $result = $this->database->select($sql, $parameters, 'all');
- if (is_array($result) && @sizeof($result) != 0) {
- foreach ($result as $row) {
- if ($row['domain_setting_value'] != '') {
- $smtp[str_replace('smtp_','',$row["domain_setting_subcategory"])] = $row['domain_setting_value'];
+ foreach ($this->recipients as $recipient) {
+ if (is_array($recipient)) { // check if each recipient has multiple fields
+ if ($recipient["address"] != '' && valid_email($recipient["address"])) { // check if valid address
+ switch ($recipient["delivery"]) {
+ case "cc" :
+ $mail->AddCC($recipient["address"], ($recipient["name"]) ? $recipient["name"] : $recipient["address"]);
+ break;
+ case "bcc" :
+ $mail->AddBCC($recipient["address"], ($recipient["name"]) ? $recipient["name"] : $recipient["address"]);
+ break;
+ default :
+ $mail->AddAddress($recipient["address"], ($recipient["name"]) ? $recipient["name"] : $recipient["address"]);
}
- }
- }
- unset($sql, $parameters, $result, $row);
-
- //value adjustments
- $smtp['auth'] = ($smtp['auth'] == "true") ? true : false;
- $smtp['password'] = ($smtp['password'] != '') ? $smtp['password'] : null;
- $smtp['secure'] = ($smtp['secure'] != "none") ? $smtp['secure'] : null;
- $smtp['username'] = ($smtp['username'] != '') ? $smtp['username'] : null;
-
- //create the email object and set general settings
- $mail = new PHPMailer();
- $mail->IsSMTP();
- if (!empty($smtp['hostname'])) {
- $mail->Hostname = $smtp['hostname'];
- }
- $mail->Host = $smtp['host'];
- if (is_numeric($smtp['port'])) {
- $mail->Port = $smtp['port'];
- }
-
- if ($smtp['auth'] == "true") {
- $mail->SMTPAuth = true;
- $mail->Username = $smtp['username'];
- $mail->Password = $smtp['password'];
- }
- else {
- $mail->SMTPAuth = false;
- }
-
- $smtp_secure = true;
- if ($smtp['secure'] == "") {
- $mail->SMTPSecure = 'none';
- $mail->SMTPAutoTLS = false;
- $smtp_secure = false;
- }
- elseif ($smtp['secure'] == "none") {
- $mail->SMTPSecure = 'none';
- $mail->SMTPAutoTLS = false;
- $smtp_secure = false;
- }
- else {
- $mail->SMTPSecure = $smtp['secure'];
- }
-
- if ($smtp_secure && isset($smtp['validate_certificate']) && !$smtp['validate_certificate']) {
- //bypass certificate check e.g. for self-signed certificates
- $smtp_options['ssl']['verify_peer'] = false;
- $smtp_options['ssl']['verify_peer_name'] = false;
- $smtp_options['ssl']['allow_self_signed'] = true;
- }
-
- //used to set the SSL version
- if ($smtp_secure && isset($smtp['crypto_method'])) {
- $smtp_options['ssl']['crypto_method'] = $smtp['crypto_method'];
- }
-
- //add SMTP Options if the array exists
- if (is_array($smtp_options)) {
- $mail->SMTPOptions = $smtp_options;
- }
-
- $this->from_address = ($this->from_address != '') ? $this->from_address : $smtp['from'];
- $this->from_name = ($this->from_name != '') ? $this->from_name : $smtp['from_name'];
- $mail->SetFrom($this->from_address, $this->from_name);
- $mail->AddReplyTo($this->from_address, $this->from_name);
- $mail->Subject = $this->subject;
- $mail->MsgHTML($this->body);
- $mail->Priority = $this->priority;
- if ($this->read_confirmation) {
- $mail->AddCustomHeader('X-Confirm-Reading-To: '.$this->from_address);
- $mail->AddCustomHeader('Return-Receipt-To: '.$this->from_address);
- $mail->AddCustomHeader('Disposition-Notification-To: '.$this->from_address);
- }
- if (is_numeric($this->debug_level) && $this->debug_level > 0) {
- $mail->SMTPDebug = $this->debug_level;
- }
- $mail->Timeout = 20; //set the timeout (seconds)
- $mail->SMTPKeepAlive = true; //don't close the connection between messages
-
- //add the email recipients
- $address_found = false;
- if (!is_array($this->recipients)) { // must be a single or delimited recipient address(s)
- $this->recipients = str_replace(' ', '', $this->recipients);
- $this->recipients = str_replace(',', ';', $this->recipients);
- $this->recipients = explode(';', $this->recipients); // convert to array of addresses
- }
-
- foreach ($this->recipients as $recipient) {
- if (is_array($recipient)) { // check if each recipient has multiple fields
- if ($recipient["address"] != '' && valid_email($recipient["address"])) { // check if valid address
- switch ($recipient["delivery"]) {
- case "cc" : $mail->AddCC($recipient["address"], ($recipient["name"]) ? $recipient["name"] : $recipient["address"]); break;
- case "bcc" : $mail->AddBCC($recipient["address"], ($recipient["name"]) ? $recipient["name"] : $recipient["address"]); break;
- default : $mail->AddAddress($recipient["address"], ($recipient["name"]) ? $recipient["name"] : $recipient["address"]);
- }
- $address_found = true;
- }
- }
- else if ($recipient != '' && valid_email($recipient)) { // check if recipient value is simply (only) an address
- $mail->AddAddress($recipient);
$address_found = true;
}
+ } elseif ($recipient != '' && valid_email($recipient)) { // check if recipient value is simply (only) an address
+ $mail->AddAddress($recipient);
+ $address_found = true;
}
-
- if (!$address_found) {
- $this->error = "No valid e-mail address provided.";
- return false;
- }
-
- //add email attachments
- if (is_array($this->attachments) && sizeof($this->attachments) > 0) {
- foreach ($this->attachments as $attachment) {
-
- //add the attachments
- if (file_exists($attachment['path'].'/'.$attachment['name'])) {
- $mail->AddAttachment($attachment['path'].'/'.$attachment['name'], $attachment['name'], 'base64', $attachment['mime_type']);
- }
- else {
- if ($attachment['base64']) {
- if ($attachment['cid']) {
- $mail->addStringEmbeddedImage(base64_decode($attachment['base64']), $attachment['cid'], $attachment['name'], 'base64', $attachment['mime_type']);
- }
- else {
- $mail->AddStringAttachment(base64_decode($attachment['base64']), $attachment['name'], 'base64', $attachment['mime_type']);
- }
- }
- }
- }
- }
-
- //save output to a buffer
- ob_start();
-
- //send the email
- $mail_status = $mail->Send();
-
- //get the output buffer
- $this->response = ob_get_clean();
-
- //send the email
- if (!$mail_status) {
- if (isset($mail->ErrorInfo) && !empty($mail->ErrorInfo)) {
- $this->error = $mail->ErrorInfo;
- }
- return false;
- }
-
- //cleanup the mail object
- $mail->ClearAddresses();
- $mail->SmtpClose();
- unset($mail);
- return true;
-
}
- catch (Exception $e) {
- $this->error = $mail->ErrorInfo;
+
+ if (!$address_found) {
+ $this->error = "No valid e-mail address provided.";
return false;
}
- }
- }
+ //add email attachments
+ if (is_array($this->attachments) && sizeof($this->attachments) > 0) {
+ foreach ($this->attachments as $attachment) {
+ //add the attachments
+ if (file_exists($attachment['path'] . '/' . $attachment['name'])) {
+ $mail->AddAttachment($attachment['path'] . '/' . $attachment['name'], $attachment['name'], 'base64', $attachment['mime_type']);
+ } else {
+ if ($attachment['base64']) {
+ if ($attachment['cid']) {
+ $mail->addStringEmbeddedImage(base64_decode($attachment['base64']), $attachment['cid'], $attachment['name'], 'base64', $attachment['mime_type']);
+ } else {
+ $mail->AddStringAttachment(base64_decode($attachment['base64']), $attachment['name'], 'base64', $attachment['mime_type']);
+ }
+ }
+ }
+ }
+ }
+
+ //save output to a buffer
+ ob_start();
+
+ //send the email
+ $mail_status = $mail->Send();
+
+ //get the output buffer
+ $this->response = ob_get_clean();
+
+ //send the email
+ if (!$mail_status) {
+ if (isset($mail->ErrorInfo) && !empty($mail->ErrorInfo)) {
+ $this->error = $mail->ErrorInfo;
+ }
+ return false;
+ }
+
+ //cleanup the mail object
+ $mail->ClearAddresses();
+ $mail->SmtpClose();
+ unset($mail);
+ return true;
+
+ } catch (Exception $e) {
+ $this->error = $mail->ErrorInfo;
+ return false;
+ }
+
+ }
}
+}
+
/*
$email = new email;
diff --git a/resources/classes/event_socket.php b/resources/classes/event_socket.php
index 8a29c4422c..077968b415 100644
--- a/resources/classes/event_socket.php
+++ b/resources/classes/event_socket.php
@@ -37,6 +37,7 @@ class buffer {
return $tmp;
}
}
+
//$b = new buffer;
//$b->append("hello\nworld\n");
//print($b->read_line());
@@ -44,23 +45,24 @@ class buffer {
/**
* Subscribes to the event socket of the FreeSWITCH (c) Event Socket Server
+ *
* @depends buffer::class
*/
class event_socket {
+ private static $socket = null;
+ public $fp;
/**
* Used as a flag to determine if the socket should be created automatically
+ *
* @var bool
*/
protected $auto_create;
-
private $buffer;
- public $fp;
-
- private static $socket = null;
private $config;
/**
* Create a new connection to the socket
+ *
* @param resource|false $fp
*/
public function __construct($fp = false, ?config $config = null) {
@@ -71,15 +73,59 @@ class event_socket {
}
/**
- * Ensures a closed connection on destruction of object
+ * Sends an API command on the socket
+ *
+ * @param string $api_cmd
+ *
+ * @return string|false Response from server or false if failed
*/
- public function __destructor() {
- $this->close();
+ public static function api(string $api_cmd) {
+ return self::command('api ' . $api_cmd);
+ }
+
+ /**
+ * Sends a command on the socket blocking for a response
+ *
+ * @param string $cmd
+ *
+ * @return string|false Response from server or false if failed
+ */
+ public static function command(string $cmd) {
+ return self::create()->request($cmd);
+ }
+
+ /**
+ * Send a command to the FreeSWITCH Event Socket Server
+ *
Multi-line commands can be sent when separated by '\n'
+ *
+ * @param string $cmd Command to send through the socket
+ *
+ * @return mixed Returns the response from FreeSWITCH or false if not connected
+ * @depends read_event()
+ */
+ public function request($cmd) {
+ if (!$this->connected()) {
+ return false;
+ }
+
+ $cmd_array = explode("\n", $cmd);
+ foreach ($cmd_array as $value) {
+ fputs($this->fp, $value . "\n");
+ }
+ fputs($this->fp, "\n"); //second line feed to end the headers
+
+ $event = $this->read_event();
+
+ if (array_key_exists('$', $event)) {
+ return $event['$'];
+ }
+ return $event;
}
/**
* Read the event body from the socket
- * @return string|false Content body or false if not connected or empty message
+ *
+ * @return mixed Content body or false if not connected or empty message
* @depends buffer::class
*/
public function read_event() {
@@ -88,7 +134,7 @@ class event_socket {
}
$b = $this->buffer;
- $content = array();
+ $content = [];
while (true) {
$line = $b->read_line();
@@ -96,7 +142,7 @@ class event_socket {
if ($line === '') {
break;
}
- list($key, $value) = explode(':', $line, 2);
+ [$key, $value] = explode(':', $line, 2);
$content[trim($key)] = trim($value);
}
@@ -132,14 +178,41 @@ class event_socket {
return $content;
}
+ /**
+ * Create uses a singleton design to return a connected socket to the FreeSWITCH Event Socket Layer
+ *
+ * @param string $host Host or IP address of FreeSWITCH event socket server. Defaults to 127.0.0.1
+ * @param string $port Port number of FreeSWITCH event socket server. Defaults to 8021
+ * @param string $password Password of FreeSWITCH event socket server. Defaults to ClueCon
+ * @param int $timeout_microseconds Number of microseconds before timeout is triggered on socket
+ *
+ * @return self
+ * @global array $conf Global configuration used in config.conf
+ */
+ public static function create($host = null, $port = null, $password = null, $timeout_microseconds = 30000): self {
+ //create the event socket object
+ if (self::$socket === null) {
+ self::$socket = new event_socket();
+ }
+ //attempt to connect it
+ if (!self::$socket->connected()) {
+ self::$socket->connect($host, $port, $password, $timeout_microseconds);
+ }
+ return self::$socket;
+ }
+
/**
* Connect to the FreeSWITCH (c) event socket server
*
If the configuration is not loaded then the defaults of
* host 127.0.0.1, port of 8021, and default password of ClueCon will be used
- * @param null|string $host Host or IP address of FreeSWITCH event socket server. Defaults to 127.0.0.1
- * @param null|string|int $port Port number of FreeSWITCH event socket server. Defaults to 8021
- * @param null|string $password Password of FreeSWITCH event socket server. Defaults to ClueCon
- * @param int $timeout_microseconds Number of microseconds before timeout is triggered on socket. Defaults to 30,000
+ *
+ * @param null|string $host Host or IP address of FreeSWITCH event socket server. Defaults to
+ * 127.0.0.1
+ * @param null|string|int $port Port number of FreeSWITCH event socket server. Defaults to 8021
+ * @param null|string $password Password of FreeSWITCH event socket server. Defaults to ClueCon
+ * @param int $timeout_microseconds Number of microseconds before timeout is triggered on socket.
+ * Defaults to 30,000
+ *
* @return bool Returns true on success or false if not connected
*/
public function connect($host = null, $port = null, $password = null, $timeout_microseconds = 30000) {
@@ -165,7 +238,7 @@ class event_socket {
//wait auth request and send a response
while ($this->connected()) {
$event = $this->read_event();
- if(($event['Content-Type'] ?? '') === 'auth/request'){
+ if (($event['Content-Type'] ?? '') === 'auth/request') {
fputs($this->fp, "auth $password\n\n");
break;
}
@@ -186,8 +259,60 @@ class event_socket {
return $this->connected();
}
+ /**
+ * Sends an API command to FreeSWITCH using asynchronous (non-blocking) mode
+ *
+ * @param string $cmd API command to send
+ *
+ * @returns string $job_id the Job ID for tracking completion status
+ */
+ public static function async(string $cmd) {
+ return self::command('bgapi ' . $cmd);
+ }
+
+ /**
+ * Ensures a closed connection on destruction of object
+ */
+ public function __destructor() {
+ $this->close();
+ }
+
+ /**
+ * Close the socket connection with the FreeSWITCH Event Socket Server.
+ *
+ * @return void
+ */
+ public function close() {
+ //fp is public access so ensure it is a resource before closing it
+ if (is_resource($this->fp)) {
+ try {
+ fclose($this->fp);
+ } catch (Exception $t) {
+ //report it
+ trigger_error("event_socket failed to close socket", E_USER_WARNING);
+ }
+ } else {
+ //log an error if fp was set to something other than a resource
+ if ($this->fp !== false) {
+ trigger_error("event_socket not a resource", E_USER_ERROR);
+ }
+ }
+ //force fp to be false
+ $this->fp = false;
+ }
+
+ /**
+ * alias of connected
+ *
+ * @return bool
+ */
+ public function is_connected(): bool {
+ return $this->connected();
+ }
+
/**
* Tests if connected to the FreeSWITCH Event Socket Server
+ *
* @return bool Returns true when connected or false when not connected
*/
public function connected(): bool {
@@ -203,124 +328,20 @@ class event_socket {
return true;
}
- /**
- * alias of connected
- * @return bool
- */
- public function is_connected(): bool {
- return $this->connected();
- }
-
- /**
- * Send a command to the FreeSWITCH Event Socket Server
- *
Multi-line commands can be sent when separated by '\n'
- * @param string $cmd Command to send through the socket
- * @return mixed Returns the response from FreeSWITCH or false if not connected
- * @depends read_event()
- */
- public function request($cmd) {
- if (!$this->connected()) {
- return false;
- }
-
- $cmd_array = explode("\n", $cmd);
- foreach ($cmd_array as $value) {
- fputs($this->fp, $value."\n");
- }
- fputs($this->fp, "\n"); //second line feed to end the headers
-
- $event = $this->read_event();
-
- if (array_key_exists('$', $event)) {
- return $event['$'];
- }
- return $event;
- }
-
/**
* Sets the current socket resource returning the old
+ *
* @param resource|bool $fp Sets the current FreeSWITCH resource
+ *
* @return mixed Returns the original resource
* @deprecated since version 5.1
*/
- public function reset_fp($fp = false){
+ public function reset_fp($fp = false) {
$tmp = $this->fp;
$this->fp = $fp;
return $tmp;
}
-
- /**
- * Closes the socket
- */
- public function close() {
- //fp is public access so ensure it is a resource before closing it
- if (is_resource($this->fp)) {
- try {
- fclose($this->fp);
- } catch (\Exception $t) {
- //report it
- trigger_error("event_socket failed to close socket", E_USER_WARNING);
- }
- } else {
- //log an error if fp was set to something other than a resource
- if ($this->fp !== false) {
- trigger_error("event_socket not a resource", E_USER_ERROR);
- }
- }
- //force fp to be false
- $this->fp = false;
- }
-
- /**
- * Create uses a singleton design to return a connected socket to the FreeSWITCH Event Socket Layer
- * @global array $conf Global configuration used in config.conf
- * @param string $host Host or IP address of FreeSWITCH event socket server. Defaults to 127.0.0.1
- * @param string $port Port number of FreeSWITCH event socket server. Defaults to 8021
- * @param string $password Password of FreeSWITCH event socket server. Defaults to ClueCon
- * @param int $timeout_microseconds Number of microseconds before timeout is triggered on socket
- * @return self
- */
- public static function create($host = null, $port = null, $password = null, $timeout_microseconds = 30000): self {
- //create the event socket object
- if (self::$socket === null) {
- self::$socket = new event_socket();
- }
- //attempt to connect it
- if(!self::$socket->connected()) {
- self::$socket->connect($host, $port, $password, $timeout_microseconds);
- }
- return self::$socket;
- }
-
- /**
- * Sends a command on the socket blocking for a response
- * @param string $cmd
- * @return string|false Response from server or false if failed
- */
- public static function command(string $cmd) {
- return self::create()->request($cmd);
- }
-
- /**
- * Sends an API command on the socket
- * @param string $api_cmd
- * @return string|false Response from server or false if failed
- */
- public static function api(string $api_cmd) {
- return self::command('api '.$api_cmd);
- }
-
- /**
- * Sends an API command to FreeSWITCH using asynchronous (non-blocking) mode
- * @param string $cmd API command to send
- * @returns string $job_id the Job ID for tracking completion status
- */
- public static function async(string $cmd) {
- return self::command('bgapi '.$cmd);
- }
}
// $esl = event_socket::create('127.0.0.1', 8021, 'ClueCon');
// print($esl->request('api sofia status'));
-
-?>
diff --git a/resources/classes/file.php b/resources/classes/file.php
index 02344545be..45f9e01777 100644
--- a/resources/classes/file.php
+++ b/resources/classes/file.php
@@ -1,58 +1,122 @@
domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
- $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? '';
+ public function __construct(array $setting_array = []) {
+ //set domain and user UUIDs
+ $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
+ $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? '';
- //set objects
- $this->database = $setting_array['database'] ?? database::new();
- $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
+ //set objects
+ $this->database = $setting_array['database'] ?? database::new();
+ $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
}
/**
- * Glob search for a list of files
- * @var string $dir this is the directory to scan
- * @var boolean $recursive get the sub directories
- * @return array list of files or an empty array if not found
+ * Returns an array of sound files.
+ *
+ * This method retrieves a list of sound files based on the provided language,
+ * dialect, and voice settings. If no specific values are provided, default values
+ * will be used.
+ *
+ * @param string $language The desired language (default: 'en').
+ * @param string $dialect The desired dialect (default: 'us').
+ * @param string $voice The desired voice (default: 'callie').
+ *
+ * @return array An array of sound files.
+ */
+ public function sounds($language = 'en', $dialect = 'us', $voice = 'callie') {
+ //define an empty array
+ $array = [];
+
+ //set default values
+ if (!isset($language)) {
+ $language = 'en';
+ }
+ if (!isset($dialect)) {
+ $dialect = 'us';
+ }
+ if (!isset($voice)) {
+ $voice = 'callie';
+ }
+
+ //set the variables
+ if (!empty($this->settings->get('switch', 'sounds')) && file_exists($this->settings->get('switch', 'sounds'))) {
+ $dir = $this->settings->get('switch', 'sounds') . '/' . $language . '/' . $dialect . '/' . $voice;
+ $rate = '8000';
+ $files = $this->glob($dir . '/*/' . $rate, true);
+ }
+
+ //loop through the languages
+ if (!empty($files)) {
+ foreach ($files as $file) {
+ $file = substr($file, strlen($dir) + 1);
+ $file = str_replace("/" . $rate, "", $file);
+ $array[] = $file;
+ }
+ }
+
+ //return the list of sounds
+ return $array;
+ }
+
+ /**
+ * Finds files in the specified directory.
+ *
+ * This method recursively searches for files and directories within the given
+ * directory, returning an array of paths if found. If no recursion is performed,
+ * only the files directly within the directory are returned.
+ *
+ * @param string $dir The directory path to search.
+ * @param bool $recursive Whether to recursively traverse subdirectories.
+ *
+ * @return array An array of file paths found in the specified directory.
*/
public function glob($dir, $recursive): array {
$files = [];
@@ -60,7 +124,7 @@ class file {
$tree = glob(rtrim($dir, '/') . '/*');
if ($recursive) {
if (is_array($tree)) {
- foreach($tree as $file) {
+ foreach ($tree as $file) {
if (is_dir($file)) {
if ($recursive == true) {
$files[] = $this->glob($file, $recursive);
@@ -71,41 +135,8 @@ class file {
}
}
}
- return $files;
}
- }
-
-
- /**
- * Get the sounds list of search as a relative path without the rate
- */
- public function sounds($language = 'en', $dialect = 'us', $voice = 'callie') {
- //define an empty array
- $array = [];
-
- //set default values
- if (!isset($language)) { $language = 'en'; }
- if (!isset($dialect)) { $dialect = 'us'; }
- if (!isset($voice)) { $voice = 'callie'; }
-
- //set the variables
- if (!empty($this->settings->get('switch', 'sounds')) && file_exists($this->settings->get('switch', 'sounds'))) {
- $dir = $this->settings->get('switch', 'sounds').'/'.$language.'/'.$dialect.'/'.$voice;
- $rate = '8000';
- $files = $this->glob($dir.'/*/'.$rate, true);
- }
-
- //loop through the languages
- if (!empty($files)) {
- foreach($files as $file) {
- $file = substr($file, strlen($dir)+1);
- $file = str_replace("/".$rate, "", $file);
- $array[] = $file;
- }
- }
-
- //return the list of sounds
- return $array;
+ return $files;
}
}
@@ -116,5 +147,3 @@ class file {
$files = $file->sounds();
print_r($files);
*/
-
-?>
diff --git a/resources/classes/filter_chain.php b/resources/classes/filter_chain.php
index 949e58cdb8..5c245aba2c 100644
--- a/resources/classes/filter_chain.php
+++ b/resources/classes/filter_chain.php
@@ -35,7 +35,9 @@ final class filter_chain {
/**
* Builds a filter chain link for filter objects
+ *
* @param array $filters Array of filter objects
+ *
* @return filter
*/
public static function or_link(array $filters): filter {
@@ -84,6 +86,13 @@ final class filter_chain {
return $chain;
}
+ /**
+ * Builds a filter chain link for filter objects
+ *
+ * @param array $filters Array of filter objects
+ *
+ * @return filter
+ */
public static function and_link(array $filters): filter {
return new class($filters) implements filter {
private $filters;
@@ -98,7 +107,7 @@ final class filter_chain {
// Check if a filter requires a null to be returned
if ($result === null) {
return null;
- } elseif(!$result) {
+ } elseif (!$result) {
return false;
}
}
diff --git a/resources/classes/google_authenticator.php b/resources/classes/google_authenticator.php
index 99f30b07a8..e61d95bf8b 100644
--- a/resources/classes/google_authenticator.php
+++ b/resources/classes/google_authenticator.php
@@ -25,61 +25,98 @@ class google_authenticator {
self::$PIN_MODULO = pow(10, self::$PASS_CODE_LENGTH);
}
- public function checkCode($secret,$code) {
+ /**
+ * Checks if the provided code is valid based on the secret and time.
+ *
+ * @param string $secret The secret to verify against.
+ * @param string $code The code to check for validity.
+ *
+ * @return bool True if the code is valid, false otherwise.
+ */
+ public function checkCode($secret, $code) {
$time = floor(time() / 30);
- for ( $i = -1; $i <= 1; $i++) {
- if ($this->getCode($secret,$time + $i) == $code) {
+ for ($i = -1; $i <= 1; $i++) {
+ if ($this->getCode($secret, $time + $i) == $code) {
return true;
}
}
return false;
}
- public function getCode($secret,$time = null) {
+ /**
+ * Generates a PIN code based on the provided secret and time.
+ *
+ * @param string $secret The secret to use for generating the code.
+ * @param int|null $time The current time in seconds since the Unix epoch. Defaults to the current time divided
+ * by 30.
+ *
+ * @return string A six-digit PIN code.
+ */
+ public function getCode($secret, $time = null) {
if (!$time) {
$time = floor(time() / 30);
}
- $base32 = new base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', TRUE, TRUE);
+ $base32 = new base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', true, true);
$secret = $base32->decode($secret);
$time = pack("N", $time);
- $time = str_pad($time,8, chr(0), STR_PAD_LEFT);
+ $time = str_pad($time, 8, chr(0), STR_PAD_LEFT);
- $hash = hash_hmac('sha1',$time,$secret,true);
- $offset = ord(substr($hash,-1));
+ $hash = hash_hmac('sha1', $time, $secret, true);
+ $offset = ord(substr($hash, -1));
$offset = $offset & 0xF;
$truncatedHash = self::hashToInt($hash, $offset) & 0x7FFFFFFF;
- $pinValue = str_pad($truncatedHash % self::$PIN_MODULO,6,"0",STR_PAD_LEFT);;
+ $pinValue = str_pad($truncatedHash % self::$PIN_MODULO, 6, "0", STR_PAD_LEFT);
return $pinValue;
}
+ /**
+ * Converts a byte array to an integer value.
+ *
+ * @param string $bytes The byte array to convert.
+ * @param int $start The starting position in the byte array.
+ *
+ * @return int The converted integer value.
+ */
protected function hashToInt($bytes, $start) {
$input = substr($bytes, $start, strlen($bytes) - $start);
- $val2 = unpack("N",substr($input,0,4));
+ $val2 = unpack("N", substr($input, 0, 4));
return $val2[1];
}
+ /**
+ * Generates a URL for the Google QR code.
+ *
+ * @param string $user The user's username.
+ * @param string $hostname The hostname of the service.
+ * @param string $secret The secret to encode in the QR code.
+ *
+ * @return string A URL that can be used to generate a QR code with the provided secret.
+ */
public function getUrl($user, $hostname, $secret) {
$url = sprintf("otpauth://totp/%s@%s?secret=%s", $user, $hostname, $secret);
$encoder = "https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=";
- $encoderURL = sprintf( "%sotpauth://totp/%s@%s&secret=%s",$encoder, $user, $hostname, $secret);
+ $encoderURL = sprintf("%sotpauth://totp/%s@%s&secret=%s", $encoder, $user, $hostname, $secret);
return $encoderURL;
}
+ /**
+ * Generates a secret based on random characters and converts it to Base32.
+ *
+ * @return string The generated secret in Base32 format.
+ */
public function generateSecret() {
$secret = "";
- for($i = 1; $i<= self::$SECRET_LENGTH;$i++) {
- $c = rand(0,255);
- $secret .= pack("c",$c);
+ for ($i = 1; $i <= self::$SECRET_LENGTH; $i++) {
+ $c = rand(0, 255);
+ $secret .= pack("c", $c);
}
- $base32 = new base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', TRUE, TRUE);
- return $base32->encode($secret);
+ $base32 = new base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', true, true);
+ return $base32->encode($secret);
}
}
-
-?>
diff --git a/resources/classes/groups.php b/resources/classes/groups.php
index e1e0bec385..f11c076f3a 100644
--- a/resources/classes/groups.php
+++ b/resources/classes/groups.php
@@ -28,516 +28,557 @@
* groups class provides methods for add, delete groups, and add default groups
*
*/
- class groups {
+class groups {
- /**
- * 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 public variables
- */
- public $group_uuid;
- public $group_level;
+ /**
+ * declare public variables
+ */
+ public $group_uuid;
+ public $group_level;
- /**
- * declare private variables
- */
- private $database;
- private $groups;
- private $name;
- private $table;
- private $toggle_field;
- private $toggle_values;
- private $location;
- private $user_uuid;
- private $domain_uuid;
+ /**
+ * declare private variables
+ */
+ private $database;
+ private $groups;
+ private $name;
+ private $table;
+ private $toggle_field;
+ private $toggle_values;
+ private $location;
+ private $user_uuid;
+ private $domain_uuid;
- /**
- * called when the object is created
- */
- public function __construct(?database $database = null, $domain_uuid = null, $user_uuid = null) {
+ /**
+ * Initializes the object with database connection, domain UUID and user UUID.
+ *
+ * @param database|null $database Database instance or null to use default
+ * @param string|null $domain_uuid Domain UUID or null to set later
+ * @param string|null $user_uuid User UUID or null to set later
+ */
+ public function __construct(?database $database = null, $domain_uuid = null, $user_uuid = null) {
- //handle the database object
- $this->database = $database ?? database::new();
+ //handle the database object
+ $this->database = $database ?? database::new();
- //set the domain_uuid
- if (is_uuid($domain_uuid)) {
- $this->domain_uuid = $domain_uuid;
- }
+ //set the domain_uuid
+ if (is_uuid($domain_uuid)) {
+ $this->domain_uuid = $domain_uuid;
+ }
- //set the user_uuid
- if (is_uuid($user_uuid)) {
- $this->user_uuid = $user_uuid;
- }
+ //set the user_uuid
+ if (is_uuid($user_uuid)) {
+ $this->user_uuid = $user_uuid;
+ }
- //get the list of groups the user is a member of
- if (!empty($this->domain_uuid) && !empty($this->user_uuid)) {
- //get the groups and save them to the groups variable
- $this->groups = $this->assigned();
+ //get the list of groups the user is a member of
+ if (!empty($this->domain_uuid) && !empty($this->user_uuid)) {
+ //get the groups and save them to the groups variable
+ $this->groups = $this->assigned();
- //get the users group level
- $group_level = 0;
- foreach ($this->groups as $row) {
- if ($this->group_level < $row['group_level']) {
- $this->group_level = $row['group_level'];
- }
+ //get the users group level
+ $group_level = 0;
+ foreach ($this->groups as $row) {
+ if ($this->group_level < $row['group_level']) {
+ $this->group_level = $row['group_level'];
}
}
}
-
- /**
- * get the list of groups the user is assigned to
- */
- public function get_groups() {
- //return the groups
- return $this->groups;
- }
-
- /**
- * delete rows from the database
- */
- public function delete($records) {
- //assign the variables
- $this->name = 'group';
- $this->table = 'groups';
- $this->location = 'groups.php';
-
- 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 array of checked records
- foreach ($records as $x => $record) {
- if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
- $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid'];
- $array['group_permissions'][$x][$this->name.'_uuid'] = $record['uuid'];
- }
- }
-
- //delete the checked rows
- 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');
-
- //set message
- message::add($text['message-delete']);
- }
- unset($records);
- }
- }
- }
-
- public function delete_members($records) {
- //assign the variables
- $this->name = 'group_member';
- $this->table = 'user_groups';
- $this->location = 'group_members.php?group_uuid='.$this->group_uuid;
-
- 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 array of checked records
- foreach ($records as $x => $record) {
- if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
- $array[$this->table][$x]['user_uuid'] = $record['uuid'];
- $array[$this->table][$x]['group_uuid'] = $this->group_uuid;
- }
- }
-
- //delete the checked rows
- if (is_array($array) && @sizeof($array) != 0) {
-
- //grant temporary permissions
- $p = permissions::new();
- $p->add('user_group_delete', 'temp');
-
- //execute delete
- $this->database->delete($array);
- unset($array);
-
- //revoke temporary permissions
- $p->delete('user_group_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 = 'group';
- $this->table = 'groups';
- $this->toggle_field = 'group_protected';
- $this->toggle_values = ['true','false'];
- $this->location = 'groups.php';
-
- 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 (domain_uuid = :domain_uuid or domain_uuid is null) ";
- $sql .= "and ".$this->name."_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) {
- //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 = 'group';
- $this->table = 'groups';
- $this->location = 'groups.php';
-
- 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['uuid'])) {
- $uuids[] = "'".$record['uuid']."'";
- }
- }
-
- //create the array from existing data
- if (is_array($uuids) && @sizeof($uuids) != 0) {
-
- //primary table
- $sql = "select * from v_".$this->table." ";
- $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) ";
- $sql .= "and ".$this->name."_uuid in (".implode(', ', $uuids).") ";
- $parameters['domain_uuid'] = $this->domain_uuid;
- $rows = $this->database->select($sql, $parameters, 'all');
- if (is_array($rows) && @sizeof($rows) != 0) {
- $y = 0;
- foreach ($rows as $x => $row) {
- $primary_uuid = uuid();
-
- //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->name.'_uuid'] = $primary_uuid;
- $array[$this->table][$x][$this->name.'_description'] = trim($row[$this->name.'_description']).' ('.$text['label-copy'].')';
-
- //permissions sub table
- $sql_2 = "select * from v_group_permissions where group_uuid = :group_uuid";
- $parameters_2['group_uuid'] = $row['group_uuid'];
- $rows_2 = $this->database->select($sql_2, $parameters_2, 'all');
- if (is_array($rows_2) && @sizeof($rows_2) != 0) {
- foreach ($rows_2 as $row_2) {
- //convert boolean values to a string
- foreach($row_2 as $key => $value) {
- if (gettype($value) == 'boolean') {
- $value = $value ? 'true' : 'false';
- $row_2[$key] = $value;
- }
- }
-
- //copy data
- $array['group_permissions'][$y] = $row_2;
-
- //overwrite
- $array['group_permissions'][$y]['group_permission_uuid'] = uuid();
- $array['group_permissions'][$y]['group_uuid'] = $primary_uuid;
-
- //increment
- $y++;
-
- }
- }
- unset($sql_2, $parameters_2, $rows_2, $row_2);
- }
- }
- 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);
- }
- }
- }
-
-
- /**
- * add defaults groups
- */
- public function defaults() {
-
- //if the are no groups add the default groups
- $sql = "select * from v_groups ";
- $sql .= "where domain_uuid is null ";
- $result = $this->database->select($sql, null, 'all');
- if (count($result) == 0) {
- $x = 0;
- $array['groups'][$x]['group_uuid'] = uuid();
- $array['groups'][$x]['domain_uuid'] = null;
- $array['groups'][$x]['group_name'] = 'superadmin';
- $array['groups'][$x]['group_level'] = '80';
- $array['groups'][$x]['group_description'] = 'Super Administrator Group';
- $array['groups'][$x]['group_protected'] = 'false';
- $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
- $x++;
- $array['groups'][$x]['group_uuid'] = uuid();
- $array['groups'][$x]['domain_uuid'] = null;
- $array['groups'][$x]['group_name'] = 'admin';
- $array['groups'][$x]['group_level'] = '50';
- $array['groups'][$x]['group_description'] = 'Administrator Group';
- $array['groups'][$x]['group_protected'] = 'false';
- $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
- $x++;
- $array['groups'][$x]['group_uuid'] = uuid();
- $array['groups'][$x]['domain_uuid'] = null;
- $array['groups'][$x]['group_name'] = 'user';
- $array['groups'][$x]['group_level'] = '30';
- $array['groups'][$x]['group_description'] = 'User Group';
- $array['groups'][$x]['group_protected'] = 'false';
- $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
- $x++;
- $array['groups'][$x]['group_uuid'] = uuid();
- $array['groups'][$x]['domain_uuid'] = null;
- $array['groups'][$x]['group_name'] = 'agent';
- $array['groups'][$x]['group_level'] = '20';
- $array['groups'][$x]['group_description'] = 'Call Center Agent Group';
- $array['groups'][$x]['group_protected'] = 'false';
- $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
- $x++;
- $array['groups'][$x]['group_uuid'] = uuid();
- $array['groups'][$x]['domain_uuid'] = null;
- $array['groups'][$x]['group_name'] = 'fax';
- $array['groups'][$x]['group_level'] = '20';
- $array['groups'][$x]['group_description'] = 'Fax User Group';
- $array['groups'][$x]['group_protected'] = 'false';
- $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
- $x++;
- $array['groups'][$x]['group_uuid'] = uuid();
- $array['groups'][$x]['domain_uuid'] = null;
- $array['groups'][$x]['group_name'] = 'public';
- $array['groups'][$x]['group_level'] = '10';
- $array['groups'][$x]['group_description'] = 'Public Group';
- $array['groups'][$x]['group_protected'] = 'false';
- $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
-
- //add the temporary permissions
- $p = permissions::new();
- $p->add("group_add", "temp");
- $p->add("group_edit", "temp");
-
- //save the data to the database
- $this->database->save($array);
- unset($array);
-
- //remove the temporary permission
- $p->delete("group_add", "temp");
- $p->delete("group_edit", "temp");
- }
- unset($result);
-
- //if there are no permissions listed in v_group_permissions then set the default permissions
- $sql = "select count(*) from v_group_permissions ";
- $sql .= "where domain_uuid is null ";
- $num_rows = $this->database->select($sql, null, 'column');
- if ($num_rows == 0) {
- //build the apps array
- $config_list = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_config.php");
- $x = 0;
- foreach ($config_list as $config_path) {
- include($config_path);
- $x++;
- }
-
- //no permissions found add the defaults
- foreach ($apps as $app) {
- if (is_array($app['permissions'])) foreach ($app['permissions'] as $row) {
- if (is_array($row['groups'])) foreach ($row['groups'] as $group) {
- $x++;
- $array['group_permissions'][$x]['group_permission_uuid'] = uuid();
- $array['group_permissions'][$x]['domain_uuid'] = null;
- $array['group_permissions'][$x]['permission_name'] = $row['name'];
- $array['group_permissions'][$x]['permission_protected'] = 'false';
- $array['group_permissions'][$x]['permission_assigned'] = 'true';
- $array['group_permissions'][$x]['group_name'] = $group;
- $array['group_permissions'][$x]['group_uuid'] = $group_uuids[$group];
- }
- }
- }
- unset($group_uuids);
-
- //add the temporary permissions
- $p = permissions::new();
- $p->add("group_permission_add", "temp");
- $p->add("group_permission_edit", "temp");
-
- //save the data to the database
- $this->database->save($array);
- unset($array);
-
- //remove the temporary permission
- $p->delete("group_permission_add", "temp");
- $p->delete("group_permission_edit", "temp");
- }
- }
-
- /**
- * get the groups assigned to the user
- */
- public function assigned() {
- $sql = "select ";
- $sql .= "u.user_group_uuid, ";
- $sql .= "u.domain_uuid, ";
- $sql .= "u.user_uuid, ";
- $sql .= "u.group_uuid, ";
- $sql .= "g.group_name, ";
- $sql .= "g.group_level ";
- $sql .= "from ";
- $sql .= "v_user_groups as u, ";
- $sql .= "v_groups as g ";
- $sql .= "where u.domain_uuid = :domain_uuid ";
- $sql .= "and u.user_uuid = :user_uuid ";
- $sql .= "and u.group_uuid = g.group_uuid ";
- $parameters['domain_uuid'] = $this->domain_uuid;
- $parameters['user_uuid'] = $this->user_uuid;
- $groups = $this->database->select($sql, $parameters, 'all');
- unset($sql, $parameters);
- if (!empty($groups)) {
- return $groups;
- }
- else {
- return [];
- }
- }
-
- /**
- * add the assigned groups to the session array
- */
- public function session() {
- $_SESSION["groups"] = $this->groups;
- $_SESSION["user"]["groups"] = $this->groups;
- $_SESSION["user"]["group_level"] = $this->group_level;
- }
}
+
+ /**
+ * Retrieves assigned user groups for a given user.
+ *
+ * This method executes a SQL query to retrieve the assigned user groups
+ * for the specified domain and user. The results are returned as an array.
+ *
+ * @return array|null An array of assigned user groups, or null if no groups are assigned.
+ */
+ public function assigned() {
+ $sql = "select ";
+ $sql .= "u.user_group_uuid, ";
+ $sql .= "u.domain_uuid, ";
+ $sql .= "u.user_uuid, ";
+ $sql .= "u.group_uuid, ";
+ $sql .= "g.group_name, ";
+ $sql .= "g.group_level ";
+ $sql .= "from ";
+ $sql .= "v_user_groups as u, ";
+ $sql .= "v_groups as g ";
+ $sql .= "where u.domain_uuid = :domain_uuid ";
+ $sql .= "and u.user_uuid = :user_uuid ";
+ $sql .= "and u.group_uuid = g.group_uuid ";
+ $parameters['domain_uuid'] = $this->domain_uuid;
+ $parameters['user_uuid'] = $this->user_uuid;
+ $groups = $this->database->select($sql, $parameters, 'all');
+ unset($sql, $parameters);
+ if (!empty($groups)) {
+ return $groups;
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Get the groups for the current context.
+ *
+ * @return array An array of group information.
+ */
+ public function get_groups() {
+ //return the groups
+ return $this->groups;
+ }
+
+ /**
+ * Delete multiple group member records.
+ *
+ * @param array $records Array of checked records to delete.
+ *
+ * @return void
+ */
+ public function delete_members($records) {
+ //assign the variables
+ $this->name = 'group_member';
+ $this->table = 'user_groups';
+ $this->location = 'group_members.php?group_uuid=' . $this->group_uuid;
+
+ 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 array of checked records
+ foreach ($records as $x => $record) {
+ if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
+ $array[$this->table][$x]['user_uuid'] = $record['uuid'];
+ $array[$this->table][$x]['group_uuid'] = $this->group_uuid;
+ }
+ }
+
+ //delete the checked rows
+ if (is_array($array) && @sizeof($array) != 0) {
+
+ //grant temporary permissions
+ $p = permissions::new();
+ $p->add('user_group_delete', 'temp');
+
+ //execute delete
+ $this->database->delete($array);
+ unset($array);
+
+ //revoke temporary permissions
+ $p->delete('user_group_delete', 'temp');
+
+ //set message
+ message::add($text['message-delete']);
+ }
+ 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($records) {
+ //assign the variables
+ $this->name = 'group';
+ $this->table = 'groups';
+ $this->location = 'groups.php';
+
+ 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 array of checked records
+ foreach ($records as $x => $record) {
+ if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
+ $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid'];
+ $array['group_permissions'][$x][$this->name . '_uuid'] = $record['uuid'];
+ }
+ }
+
+ //delete the checked rows
+ 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');
+
+ //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 = 'group';
+ $this->table = 'groups';
+ $this->toggle_field = 'group_protected';
+ $this->toggle_values = ['true', 'false'];
+ $this->location = 'groups.php';
+
+ 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 (domain_uuid = :domain_uuid or domain_uuid is null) ";
+ $sql .= "and " . $this->name . "_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) {
+ //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 = 'group';
+ $this->table = 'groups';
+ $this->location = 'groups.php';
+
+ 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['uuid'])) {
+ $uuids[] = "'" . $record['uuid'] . "'";
+ }
+ }
+
+ //create the array from existing data
+ if (is_array($uuids) && @sizeof($uuids) != 0) {
+
+ //primary table
+ $sql = "select * from v_" . $this->table . " ";
+ $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) ";
+ $sql .= "and " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") ";
+ $parameters['domain_uuid'] = $this->domain_uuid;
+ $rows = $this->database->select($sql, $parameters, 'all');
+ if (is_array($rows) && @sizeof($rows) != 0) {
+ $y = 0;
+ foreach ($rows as $x => $row) {
+ $primary_uuid = uuid();
+
+ //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->name . '_uuid'] = $primary_uuid;
+ $array[$this->table][$x][$this->name . '_description'] = trim($row[$this->name . '_description']) . ' (' . $text['label-copy'] . ')';
+
+ //permissions sub table
+ $sql_2 = "select * from v_group_permissions where group_uuid = :group_uuid";
+ $parameters_2['group_uuid'] = $row['group_uuid'];
+ $rows_2 = $this->database->select($sql_2, $parameters_2, 'all');
+ if (is_array($rows_2) && @sizeof($rows_2) != 0) {
+ foreach ($rows_2 as $row_2) {
+ //convert boolean values to a string
+ foreach ($row_2 as $key => $value) {
+ if (gettype($value) == 'boolean') {
+ $value = $value ? 'true' : 'false';
+ $row_2[$key] = $value;
+ }
+ }
+
+ //copy data
+ $array['group_permissions'][$y] = $row_2;
+
+ //overwrite
+ $array['group_permissions'][$y]['group_permission_uuid'] = uuid();
+ $array['group_permissions'][$y]['group_uuid'] = $primary_uuid;
+
+ //increment
+ $y++;
+
+ }
+ }
+ unset($sql_2, $parameters_2, $rows_2, $row_2);
+ }
+ }
+ 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 default groups and permissions if none are set.
+ *
+ * This method checks for the presence of groups and group permissions in the database.
+ * If no groups or group permissions exist, it sets default values.
+ */
+ public function defaults() {
+
+ //if the are no groups add the default groups
+ $sql = "select * from v_groups ";
+ $sql .= "where domain_uuid is null ";
+ $result = $this->database->select($sql, null, 'all');
+ if (count($result) == 0) {
+ $x = 0;
+ $array['groups'][$x]['group_uuid'] = uuid();
+ $array['groups'][$x]['domain_uuid'] = null;
+ $array['groups'][$x]['group_name'] = 'superadmin';
+ $array['groups'][$x]['group_level'] = '80';
+ $array['groups'][$x]['group_description'] = 'Super Administrator Group';
+ $array['groups'][$x]['group_protected'] = 'false';
+ $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
+ $x++;
+ $array['groups'][$x]['group_uuid'] = uuid();
+ $array['groups'][$x]['domain_uuid'] = null;
+ $array['groups'][$x]['group_name'] = 'admin';
+ $array['groups'][$x]['group_level'] = '50';
+ $array['groups'][$x]['group_description'] = 'Administrator Group';
+ $array['groups'][$x]['group_protected'] = 'false';
+ $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
+ $x++;
+ $array['groups'][$x]['group_uuid'] = uuid();
+ $array['groups'][$x]['domain_uuid'] = null;
+ $array['groups'][$x]['group_name'] = 'user';
+ $array['groups'][$x]['group_level'] = '30';
+ $array['groups'][$x]['group_description'] = 'User Group';
+ $array['groups'][$x]['group_protected'] = 'false';
+ $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
+ $x++;
+ $array['groups'][$x]['group_uuid'] = uuid();
+ $array['groups'][$x]['domain_uuid'] = null;
+ $array['groups'][$x]['group_name'] = 'agent';
+ $array['groups'][$x]['group_level'] = '20';
+ $array['groups'][$x]['group_description'] = 'Call Center Agent Group';
+ $array['groups'][$x]['group_protected'] = 'false';
+ $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
+ $x++;
+ $array['groups'][$x]['group_uuid'] = uuid();
+ $array['groups'][$x]['domain_uuid'] = null;
+ $array['groups'][$x]['group_name'] = 'fax';
+ $array['groups'][$x]['group_level'] = '20';
+ $array['groups'][$x]['group_description'] = 'Fax User Group';
+ $array['groups'][$x]['group_protected'] = 'false';
+ $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
+ $x++;
+ $array['groups'][$x]['group_uuid'] = uuid();
+ $array['groups'][$x]['domain_uuid'] = null;
+ $array['groups'][$x]['group_name'] = 'public';
+ $array['groups'][$x]['group_level'] = '10';
+ $array['groups'][$x]['group_description'] = 'Public Group';
+ $array['groups'][$x]['group_protected'] = 'false';
+ $group_uuids[$array['groups'][$x]['group_name']] = $array['groups'][$x]['group_uuid'];
+
+ //add the temporary permissions
+ $p = permissions::new();
+ $p->add("group_add", "temp");
+ $p->add("group_edit", "temp");
+
+ //save the data to the database
+ $this->database->save($array);
+ unset($array);
+
+ //remove the temporary permission
+ $p->delete("group_add", "temp");
+ $p->delete("group_edit", "temp");
+ }
+ unset($result);
+
+ //if there are no permissions listed in v_group_permissions then set the default permissions
+ $sql = "select count(*) from v_group_permissions ";
+ $sql .= "where domain_uuid is null ";
+ $num_rows = $this->database->select($sql, null, 'column');
+ if ($num_rows == 0) {
+ //build the apps array
+ $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
+ $x = 0;
+ foreach ($config_list as $config_path) {
+ include($config_path);
+ $x++;
+ }
+
+ //no permissions found add the defaults
+ foreach ($apps as $app) {
+ if (is_array($app['permissions'])) foreach ($app['permissions'] as $row) {
+ if (is_array($row['groups'])) foreach ($row['groups'] as $group) {
+ $x++;
+ $array['group_permissions'][$x]['group_permission_uuid'] = uuid();
+ $array['group_permissions'][$x]['domain_uuid'] = null;
+ $array['group_permissions'][$x]['permission_name'] = $row['name'];
+ $array['group_permissions'][$x]['permission_protected'] = 'false';
+ $array['group_permissions'][$x]['permission_assigned'] = 'true';
+ $array['group_permissions'][$x]['group_name'] = $group;
+ $array['group_permissions'][$x]['group_uuid'] = $group_uuids[$group];
+ }
+ }
+ }
+ unset($group_uuids);
+
+ //add the temporary permissions
+ $p = permissions::new();
+ $p->add("group_permission_add", "temp");
+ $p->add("group_permission_edit", "temp");
+
+ //save the data to the database
+ $this->database->save($array);
+ unset($array);
+
+ //remove the temporary permission
+ $p->delete("group_permission_add", "temp");
+ $p->delete("group_permission_edit", "temp");
+ }
+ }
+
+ /**
+ * Stores user data and groups in the session.
+ *
+ * This method populates several session variables with relevant user and group information.
+ *
+ * @return void
+ */
+ public function session() {
+ $_SESSION["groups"] = $this->groups;
+ $_SESSION["user"]["groups"] = $this->groups;
+ $_SESSION["user"]["group_level"] = $this->group_level;
+ }
+}
diff --git a/resources/classes/invalid_uuid_exception.php b/resources/classes/invalid_uuid_exception.php
index a54e6190ba..1b01bbad77 100644
--- a/resources/classes/invalid_uuid_exception.php
+++ b/resources/classes/invalid_uuid_exception.php
@@ -32,7 +32,16 @@
* @author Tim Fry
*/
class invalid_uuid_exception extends Exception {
- public function __construct(string $message = "UUID is not valid", int $code = 0, ?\Throwable $previous = null) {
- return parent::__construct($message, $code, $previous);
+ /**
+ * Constructs a new instance of the class.
+ *
+ * @param string $message The error message. Defaults to "UUID is not valid".
+ * @param int $code The HTTP status code. Defaults to 0.
+ * @param \Throwable|null $previous The previous exception, if any.
+ *
+ * @return void
+ */
+ public function __construct(string $message = "UUID is not valid", int $code = 0, ?Throwable $previous = null) {
+ parent::__construct($message, $code, $previous);
}
}
diff --git a/resources/classes/logging.php b/resources/classes/logging.php
index 2b1a4ff897..f696fbdb63 100644
--- a/resources/classes/logging.php
+++ b/resources/classes/logging.php
@@ -1,165 +1,269 @@
clear_debug();
- // declare log file and file pointer as private properties
- private $fp;
- private $debug_func;
- private $debug_line;
- private $debug_file;
- private $debug_class;
-
- public function __construct(string $filename_and_path) {
- //init values
- $this->clear_debug();
-
- try {
- //open file in append mode
- $this->fp = fopen($filename_and_path, 'a');
- } catch (Exception $ex) {
- //send the error to the caller
- throw $ex;
- }
+ try {
+ //open file in append mode
+ $this->fp = fopen($filename_and_path, 'a');
+ } catch (Exception $ex) {
+ //send the error to the caller
+ throw $ex;
}
+ }
- public function __destruct() {
- try {
- $this->flush();
- } catch (Exception $ex) {
- //do nothing
- } finally {
- //close the file
- if (is_resource($this->fp)) {
- fclose($this->fp);
- }
- }
- }
+ /**
+ * Clear debug settings
+ *
+ * @return void
+ */
+ private function clear_debug() {
+ $this->debug_line = null;
+ $this->debug_file = null;
+ $this->debug_func = null;
+ $this->debug_class = null;
+ }
- /**
- * Ensure all data arrives on disk
- * @throws Exception
- */
- public function flush() {
- try {
- //ensure everything arrives on disk
- if (is_resource($this->fp)) {
- fflush($this->fp);
- }
- } catch (Exception $ex) {
- throw $ex;
- }
- }
-
- // write message to the log file
- private function _write($msg) {
- // define current time and suppress E_WARNING if using the system TZ settings
- }
-
- private function clear_debug() {
- $this->debug_line = null;
- $this->debug_file = null;
- $this->debug_func = null;
- $this->debug_class = null;
- }
-
- /**
- * Write raw data to the
- * @param string $level
- * @param string $message
- */
- public function write(string $level, string $message) {
- $this->get_backtrace_details();
- // write current time, script name and message to the log file
- // (don't forget to set the INI setting date.timezone)
- $time = @date('Y-m-d H:i:s');
- $file = $this->debug_file ?? 'file not set';
- $line = $this->debug_line ?? '0000';
- fwrite($this->fp, "[$time] [$level] [{$file}:{$line}] $message");
- $this->clear_debug();
- }
-
- public function debug_class(?string $debug_class = null) {
- if (func_num_args() > 0) {
- $this->debug_class = $debug_class;
- return $this;
- }
- return $this->debug_class;
- }
-
- public function debug_line(?string $debug_line = null) {
- if (func_num_args() > 0) {
- $this->debug_line = $debug_line;
- return $this;
- }
- return $this->debug_line;
- }
-
- public function debug_func(?string $debug_func = null) {
- if (func_num_args() > 0) {
- $this->debug_func = $debug_func;
- return $this;
- }
- return $this->debug_func;
- }
-
- public function debug_file(?string $debug_file = null) {
- if (func_num_args() > 0) {
- $this->debug_file = $debug_file;
- return $this;
- }
- return $this->debug_file;
- }
-
- public function writeln($level, $message) {
- $this->get_backtrace_details();
- $this->write($level, $message . "\n");
- }
-
- public function debug($message) {
- $this->get_backtrace_details();
- $this->writeln("DEBUG", $message);
- }
-
- public function info($message) {
- $this->get_backtrace_details();
- $this->writeln("INFO", $message);
- }
-
- public function warning($message) {
- $this->get_backtrace_details();
- $this->writeln("WARNING", $message);
- }
-
- public function error($message) {
- $this->get_backtrace_details();
- $this->writeln("ERROR", $message);
- }
-
- private function get_backtrace_details() {
- if ($this->debug_file === null) {
- $debug = debug_backtrace();
- $ndx = count($debug) - 1;
- $this->debug_file = $debug[$ndx]['file'];
- $this->debug_line = $debug[$ndx]['line'];
- $this->debug_func = $debug[$ndx]['function'];
- $this->debug_class = $debug[$ndx]['class'] ?? '';
+ /**
+ * Clean up any resources held by this object on destruction.
+ *
+ * @throws Exception if an error occurs during flushing or closing of the file pointer.
+ */
+ public function __destruct() {
+ try {
+ $this->flush();
+ } catch (Exception $ex) {
+ //do nothing
+ } finally {
+ //close the file
+ if (is_resource($this->fp)) {
+ fclose($this->fp);
}
}
}
- /*
- * Example:
- $log = new logging(sys_get_temp_dir() . '/logging.log');
- $log->writeln("debug", "passed validation");
- $log->debug("pass");
- $log->warning("variable should not used");
- $log->debug_file(__FILE__)->debug_line(__LINE__)->write("DEBUG", "Raw message\n");
- */
\ No newline at end of file
+ // write message to the log file
+
+ /**
+ * Ensure all data arrives on disk
+ *
+ * @return void
+ * @throws Exception
+ */
+ public function flush() {
+ try {
+ //ensure everything arrives on disk
+ if (is_resource($this->fp)) {
+ fflush($this->fp);
+ }
+ } catch (Exception $ex) {
+ throw $ex;
+ }
+ }
+
+ /**
+ * Set or retrieve the class name for debugging purposes.
+ *
+ * @param string|null $debug_class The class name to set for debugging. If null, returns the current debug class.
+ *
+ * @return object This object instance for chaining.
+ */
+ public function debug_class(?string $debug_class = null) {
+ if (func_num_args() > 0) {
+ $this->debug_class = $debug_class;
+ return $this;
+ }
+ return $this->debug_class;
+ }
+
+ /**
+ * Set or retrieve the current debug line
+ *
+ * @param string|null $debug_line The new debug line to set, or null to clear it
+ *
+ * @return object|string The instance itself if a new value was provided, otherwise the current debug line as a
+ * string
+ */
+ public function debug_line(?string $debug_line = null) {
+ if (func_num_args() > 0) {
+ $this->debug_line = $debug_line;
+ return $this;
+ }
+ return $this->debug_line;
+ }
+
+ /**
+ * Sets or retrieves the current debug function.
+ *
+ * If a string argument is provided, it sets the current debug function. If no argument is provided,
+ * it returns the current debug function.
+ *
+ * @param string|null $debug_func The debug function to set (optional)
+ *
+ * @return $this Self-reference for chaining
+ */
+ public function debug_func(?string $debug_func = null) {
+ if (func_num_args() > 0) {
+ $this->debug_func = $debug_func;
+ return $this;
+ }
+ return $this->debug_func;
+ }
+
+ /**
+ * Set or retrieve the path to a debug file.
+ *
+ * @param string|null $debug_file Path to the debug file (optional)
+ *
+ * @return object|string The current object if setting the debug file, otherwise the current debug file path
+ */
+ public function debug_file(?string $debug_file = null) {
+ if (func_num_args() > 0) {
+ $this->debug_file = $debug_file;
+ return $this;
+ }
+ return $this->debug_file;
+ }
+
+ /**
+ * Write a debug message to the log along with its backtrace details
+ *
+ * @param string $message The debug message to be written
+ *
+ * @return void
+ */
+ public function debug($message) {
+ $this->get_backtrace_details();
+ $this->writeln("DEBUG", $message);
+ }
+
+ /**
+ * Get detailed backtrace information for the current call stack.
+ *
+ * If the debug file, line and function have not been cached, this method will
+ * cache them in object properties to prevent repeated calls to debug_backtrace().
+ *
+ * @return void
+ */
+ private function get_backtrace_details() {
+ if ($this->debug_file === null) {
+ $debug = debug_backtrace();
+ $ndx = count($debug) - 1;
+ $this->debug_file = $debug[$ndx]['file'];
+ $this->debug_line = $debug[$ndx]['line'];
+ $this->debug_func = $debug[$ndx]['function'];
+ $this->debug_class = $debug[$ndx]['class'] ?? '';
+ }
+ }
+
+ /**
+ * Write a message to the output with an optional level and trailing newline character.
+ *
+ * @param string $level The logging level (optional).
+ * @param string $message The message to be written.
+ */
+ public function writeln($level, $message) {
+ $this->get_backtrace_details();
+ $this->write($level, $message . "\n");
+ }
+
+ /**
+ * Write a log message to the file
+ *
+ * @param string $level The level of the log message (e.g. 'error', 'warning', etc.)
+ * @param string $message The actual log message
+ *
+ * @return void
+ */
+ public function write(string $level, string $message) {
+ $this->get_backtrace_details();
+ // write current time, script name and message to the log file
+ // (don't forget to set the INI setting date.timezone)
+ $time = @date('Y-m-d H:i:s');
+ $file = $this->debug_file ?? 'file not set';
+ $line = $this->debug_line ?? '0000';
+ fwrite($this->fp, "[$time] [$level] [{$file}:{$line}] $message");
+ $this->clear_debug();
+ }
+
+ /**
+ * Log an informational message.
+ *
+ * This method logs a message with level "INFO" and stores backtrace details for debugging purposes.
+ *
+ * @param string $message The message to be logged
+ */
+ public function info($message) {
+ $this->get_backtrace_details();
+ $this->writeln("INFO", $message);
+ }
+
+ /**
+ * Display a warning message to the user
+ *
+ * @param string $message The warning message to display
+ *
+ * @throws Exception If an error occurs while displaying the message
+ */
+ public function warning($message) {
+ $this->get_backtrace_details();
+ $this->writeln("WARNING", $message);
+ }
+
+ /**
+ * Log an error message with a backtrace.
+ *
+ * @param string $message The error message to log
+ */
+ public function error($message) {
+ $this->get_backtrace_details();
+ $this->writeln("ERROR", $message);
+ }
+
+ /**
+ * Writes a message to the underlying output stream.
+ *
+ * @param string $msg The message to be written
+ *
+ * @throws Exception If an error occurs while writing to the stream
+ */
+ private function _write($msg) {
+ // define current time and suppress E_WARNING if using the system TZ settings
+ }
+}
+
+/*
+* Example:
+$log = new logging(sys_get_temp_dir() . '/logging.log');
+$log->writeln("debug", "passed validation");
+$log->debug("pass");
+$log->warning("variable should not used");
+$log->debug_file(__FILE__)->debug_line(__LINE__)->write("DEBUG", "Raw message\n");
+*/
\ No newline at end of file
diff --git a/resources/classes/menu.php b/resources/classes/menu.php
index 47dde80697..483a498782 100644
--- a/resources/classes/menu.php
+++ b/resources/classes/menu.php
@@ -27,1485 +27,1553 @@
/**
* menu class
*/
- class menu {
+class menu {
- /**
- * declare constant variables
- */
- const app_name = 'menus';
- const app_uuid = 'f4b3b3d2-6287-489c-2a00-64529e46f2d7';
+ /**
+ * declare constant variables
+ */
+ const app_name = 'menus';
+ const app_uuid = 'f4b3b3d2-6287-489c-2a00-64529e46f2d7';
- /**
- * declare private variables
- */
- public $menu_uuid;
- public $menu_language;
- public $text;
+ /**
+ * declare private variables
+ */
+ public $menu_uuid;
+ public $menu_language;
+ public $text;
- /**
- * 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;
- /**
- * 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;
- /**
- * User 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 $user_uuid;
+ /**
+ * User 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 $user_uuid;
- /**
- * Username 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 $username;
+ /**
+ * Username 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 $username;
- /**
- * 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;
- /**
- * 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
- */
- private $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
+ */
+ private $domain_name;
- /**
- * called when the object is created
- */
- public function __construct($setting_array = []) {
- //assign the variables
- $this->location = 'menus.php';
+ /**
+ * 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($setting_array = []) {
+ //assign the variables
+ $this->location = 'menus.php';
- $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
- $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? '';
- $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? '';
- $this->username = $setting_array['username'] ?? $_SESSION['username'] ?? '';
+ $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
+ $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? '';
+ $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? '';
+ $this->username = $setting_array['username'] ?? $_SESSION['username'] ?? '';
- //open a database connection
- $this->database = $setting_array['database'] ?? database::new();
+ //open a database connection
+ $this->database = $setting_array['database'] ?? database::new();
- //load the settings
- $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
+ //load the settings
+ $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
- //add multi-lingual support
- $this->text = (new text)->get();
- }
+ //add multi-lingual support
+ $this->text = (new text)->get();
+ }
- /**
- * delete rows from the database
- */
- public function delete($records) {
- //assign the variables
- $this->name = 'menu';
- $this->table = 'menus';
+ /**
+ * Deletes one or more menu items.
+ *
+ * @param array $records An array of records to delete, where each record contains a 'uuid' key with the UUID of
+ * the item to delete, and an optional 'checked' key with a boolean value indicating whether
+ * the item is checked for deletion.
+ */
+ public function delete_items($records) {
+ //assign the variables
+ $this->name = 'menu_item';
+ $this->table = 'menu_items';
- if (permission_exists($this->name.'_delete')) {
+ if (permission_exists($this->name . '_delete')) {
- //validate the token
- $token = new token;
- if (!$token->validate($_SERVER['PHP_SELF'])) {
- message::add($this->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) {
- if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
- //remove menu languages
- $array['menu_languages'][$x][$this->name.'_uuid'] = $record['uuid'];
-
- //remove menu item groups
- $array['menu_item_groups'][$x][$this->name.'_uuid'] = $record['uuid'];
-
- //remove menu items
- $array['menu_items'][$x][$this->name.'_uuid'] = $record['uuid'];
-
- //build array to remove the menu
- $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid'];
-
- //increment
- $x++;
- }
- }
-
- //delete the checked rows
- if (is_array($array) && @sizeof($array) != 0) {
- //grant temporary permissions
- $p = permissions::new();
- $p->add('menu_item_delete', 'temp');
- $p->add('menu_item_group_delete', 'temp');
- $p->add('menu_language_delete', 'temp');
-
- //execute delete
- $this->database->delete($array);
- unset($array);
-
- //revoke temporary permissions
- $p->delete('menu_item_delete', 'temp');
- $p->delete('menu_item_group_delete', 'temp');
- $p->delete('menu_language_delete', 'temp');
-
- //set message
- message::add($this->text['message-delete']);
- }
- unset($records);
- }
+ //validate the token
+ $token = new token;
+ if (!$token->validate('/core/menu/menu_item_list.php')) {
+ message::add($this->text['message-invalid_token'], 'negative');
+ header('Location: ' . $this->location);
+ exit;
}
- }
- public function delete_items($records) {
- //assign the variables
- $this->name = 'menu_item';
- $this->table = 'menu_items';
-
- if (permission_exists($this->name.'_delete')) {
-
- //validate the token
- $token = new token;
- if (!$token->validate('/core/menu/menu_item_list.php')) {
- message::add($this->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) {
- if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
- //build array
- $uuids[] = "'".$record['uuid']."'";
- //remove menu languages
- $array['menu_languages'][$x][$this->name.'_uuid'] = $record['uuid'];
- //remove menu item groups
- $array['menu_item_groups'][$x][$this->name.'_uuid'] = $record['uuid'];
- //remove menu items
- $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid'];
- //increment
- $x++;
- }
- }
-
- //include child menu items
- if (!empty($uuids) && @sizeof($uuids) != 0) {
- $sql = "select menu_item_uuid as uuid from v_".$this->table." ";
- $sql .= "where menu_item_parent_uuid in (".implode(', ', $uuids).") ";
- $rows = $this->database->select($sql, null, 'all');
- if (!empty($rows) && @sizeof($rows) != 0) {
- foreach ($rows as $row) {
- //remove menu languages
- $array['menu_languages'][$x][$this->name.'_uuid'] = $row['uuid'];
- //remove menu item groups
- $array['menu_item_groups'][$x][$this->name.'_uuid'] = $row['uuid'];
- //remove menu items
- $array[$this->table][$x][$this->name.'_uuid'] = $row['uuid'];
- //increment
- $x++;
- }
- }
- }
-
- //delete the checked rows
- if (!empty($array) && is_array($array) && @sizeof($array) != 0) {
-
- //grant temporary permissions
- $p = permissions::new();
- $p->add('menu_language_delete', 'temp');
- $p->add('menu_item_group_delete', 'temp');
-
- //execute delete
- $this->database->delete($array);
- unset($array);
-
- //revoke temporary permissions
- $p->delete('menu_language_delete', 'temp');
- $p->delete('menu_item_group_delete', 'temp');
-
- //set message
- message::add($this->text['message-delete']);
- }
- unset($records);
- }
- }
- }
-
- /**
- * toggle a field between two values
- */
- public function toggle_items($records) {
- //assign the variables
- $this->name = 'menu_item';
- $this->table = 'menu_items';
- $this->toggle_field = 'menu_item_protected';
- $this->toggle_values = ['true','false'];
-
- if (permission_exists($this->name.'_edit')) {
-
- //validate the token
- $token = new token;
- if (!$token->validate('/core/menu/menu_item_list.php')) {
- message::add($this->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 (!empty($uuids) && 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).") ";
- $parameters = null;
- $rows = $this->database->select($sql, $parameters, 'all');
- if (is_array($rows) && @sizeof($rows) != 0) {
- foreach ($rows as $row) {
- $states[$row['uuid']] = $row['toggle'] == '' ? $this->toggle_values[1] : $row['toggle'];
- }
- }
- unset($sql, $parameters, $rows, $row);
- }
-
- //build update array
- $x = 0;
- if (!empty($states) && is_array($states) && @sizeof($states) != 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
- $x++;
- }
- }
-
- //save the changes
- if (!empty($array) && is_array($array) && @sizeof($array) != 0) {
- //save the array
- $this->database->save($array);
- unset($array);
-
- //set message
- message::add($this->text['message-toggle']);
- }
- unset($records, $states);
- }
- }
- }
-
- /**
- * delete items in the menu used by restore default
- */
- public function restore_delete() {
- //remove existing menu languages
- $sql = "delete from v_menu_languages ";
- $sql .= "where menu_uuid = :menu_uuid ";
- $sql .= "and menu_item_uuid in ( ";
- $sql .= " select menu_item_uuid ";
- $sql .= " from v_menu_items ";
- $sql .= " where menu_uuid = :menu_uuid ";
- //$sql .= " and ( ";
- //$sql .= " menu_item_protected <> 'true' ";
- //$sql .= " or menu_item_protected is null ";
- //$sql .= " ) ";
- $sql .= ") ";
- $parameters['menu_uuid'] = $this->menu_uuid;
- $this->database->execute($sql, $parameters);
- unset($sql, $parameters);
-
- //remove existing menu item groups
- $sql = "delete from v_menu_item_groups ";
- $sql .= "where menu_uuid = :menu_uuid ";
- $sql .= "and menu_item_uuid in ( ";
- $sql .= " select menu_item_uuid ";
- $sql .= " from v_menu_items ";
- $sql .= " where menu_uuid = :menu_uuid ";
- //$sql .= " and ( ";
- //$sql .= " menu_item_protected <> 'true' ";
- //$sql .= " or menu_item_protected is null ";
- //$sql .= " ) ";
- $sql .= ") ";
- $parameters['menu_uuid'] = $this->menu_uuid;
- $this->database->execute($sql, $parameters);
- unset($sql, $parameters);
-
- //remove existing menu items
- $sql = "delete from v_menu_items ";
- $sql .= "where menu_uuid = :menu_uuid ";
- //$sql .= "and ( ";
- //$sql .= " menu_item_protected <> 'true' ";
- //$sql .= " or menu_item_protected is null ";
- //$sql .= ") ";
- $parameters['menu_uuid'] = $this->menu_uuid;
- $this->database->execute($sql, $parameters);
- unset($sql, $parameters);
- }
-
- public function assign_items($records, $menu_uuid, $group_uuid) {
- //assign the variables
- $this->name = 'menu_item';
- $this->table = 'menu_items';
-
- 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('/core/menu/menu_item_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, group_uuid, menu_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['uuid'])) {
- //build array
- $uuids[] = "'".$record['uuid']."'";
- //assign menu item groups
- $array['menu_item_groups'][$x]['menu_item_group_uuid'] = uuid();
- $array['menu_item_groups'][$x]['menu_uuid'] = $menu_uuid;
- $array['menu_item_groups'][$x][$this->name.'_uuid'] = $record['uuid'];
- $array['menu_item_groups'][$x]['group_name'] = $group['group_name'];
- $array['menu_item_groups'][$x]['group_uuid'] = $group['group_uuid'];
- //increment
- $x++;
- }
- }
-
- unset($records);
-
- //exlude exist rows
- if (!empty($array) && @sizeof($array) != 0) {
- $sql = "select menu_uuid, menu_item_uuid, ";
- $sql .= "group_uuid from v_menu_item_groups ";
- $menu_item_groups = $this->database->select($sql, null, 'all');
- $array['menu_item_groups'] = array_filter($array['menu_item_groups'], function($ar) use ($menu_item_groups) {
- foreach ($menu_item_groups as $existingArrayItem) {
- if ($ar['menu_uuid'] == $existingArrayItem['menu_uuid'] && $ar['menu_item_uuid'] == $existingArrayItem['menu_item_uuid'] && $ar['group_uuid'] == $existingArrayItem['group_uuid']) {
- return false;
- }
- }
- return true;
- });
- unset($menu_item_groups);
- }
-
- //add the checked rows fro 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_items($records, $menu_uuid, $group_uuid) {
- //assign the variables
- $this->name = 'menu_item';
- $this->table = 'menu_items';
-
- 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('/core/menu/menu_item_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, group_uuid, menu_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['uuid'])) {
- //build array
- $uuids[] = "'".$record['uuid']."'";
- //assign menu item groups
- $array['menu_item_groups'][$x]['menu_uuid'] = $menu_uuid;
- $array['menu_item_groups'][$x][$this->name.'_uuid'] = $record['uuid'];
- $array['menu_item_groups'][$x]['group_name'] = $group['group_name'];
- $array['menu_item_groups'][$x]['group_uuid'] = $group['group_uuid'];
- //increment
- $x++;
- }
- }
-
- unset($records);
-
- //include child menu items and their main_uuid too
- if (!empty($uuids) && @sizeof($uuids) != 0) {
- $sql = "select menu_uuid, menu_item_uuid as uuid from v_".$this->table." ";
- $sql .= "where menu_item_parent_uuid in (".implode(', ', $uuids).") ";
- $rows = $this->database->select($sql, null, 'all');
- if (!empty($rows) && @sizeof($rows) != 0) {
- foreach ($rows as $row) {
- //assign menu item groups
- $array['menu_item_groups'][$x]['menu_uuid'] = $row['menu_uuid'];
- $array['menu_item_groups'][$x][$this->name.'_uuid'] = $row['uuid'];
- $array['menu_item_groups'][$x]['group_name'] = $group['group_name'];
- $array['menu_item_groups'][$x]['group_uuid'] = $group['group_uuid'];
- //increment
- $x++;
- }
- }
- }
-
- unset($uuids);
-
- //add the checked rows fro group
- if (!empty($array) && is_array($array) && @sizeof($array) != 0) {
- //grant temporary permissions
- $p = new permissions;
- $p->add('menu_language_delete', 'temp');
- $p->add('menu_item_group_delete', 'temp');
-
- //execute delete
- $this->database->delete($array);
- unset($array);
-
- //revoke temporary permissions
- $p->delete('menu_language_delete', 'temp');
- $p->delete('menu_item_group_delete', 'temp');
-
- //set message
- message::add($text['message-delete']);
- }
- }
- }
- }
-
- /**
- * restore the default menu
- */
- public function restore_default() {
-
- //get the $apps array from the installed apps from the core and mod directories
- $config_list = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_menu.php");
+ //delete multiple records
+ if (is_array($records) && @sizeof($records) != 0) {
+ //build the delete array
$x = 0;
- if (is_array($config_list)) {
- foreach ($config_list as $config_path) {
- $app_path = dirname($config_path);
- $app_path = preg_replace('/\A.*(\/.*\/.*)\z/', '$1', $app_path);
- $y = 0;
- try {
- //echo "[".$x ."] ".$config_path."\n";
- include($config_path);
+ foreach ($records as $record) {
+ if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
+ //build array
+ $uuids[] = "'" . $record['uuid'] . "'";
+ //remove menu languages
+ $array['menu_languages'][$x][$this->name . '_uuid'] = $record['uuid'];
+ //remove menu item groups
+ $array['menu_item_groups'][$x][$this->name . '_uuid'] = $record['uuid'];
+ //remove menu items
+ $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid'];
+ //increment
+ $x++;
+ }
+ }
+
+ //include child menu items
+ if (!empty($uuids) && @sizeof($uuids) != 0) {
+ $sql = "select menu_item_uuid as uuid from v_" . $this->table . " ";
+ $sql .= "where menu_item_parent_uuid in (" . implode(', ', $uuids) . ") ";
+ $rows = $this->database->select($sql, null, 'all');
+ if (!empty($rows) && @sizeof($rows) != 0) {
+ foreach ($rows as $row) {
+ //remove menu languages
+ $array['menu_languages'][$x][$this->name . '_uuid'] = $row['uuid'];
+ //remove menu item groups
+ $array['menu_item_groups'][$x][$this->name . '_uuid'] = $row['uuid'];
+ //remove menu items
+ $array[$this->table][$x][$this->name . '_uuid'] = $row['uuid'];
+ //increment
$x++;
}
- catch (Exception $e) {
- echo 'exception caught: ' . $e->getMessage() . "\n";
- exit;
- }
}
}
- //get the list of languages
- $language = new text;
-
- //create a uuid array of the original uuid used as the key and new uuid as the value
- if (is_array($apps)) {
- $x = 0;
- foreach ($apps as $row) {
- if (is_array($row['menu'])) {
- foreach ($row['menu'] as $menu) {
- $uuid_array[$menu['uuid']] = uuid();
- }
- }
- }
- }
-
- //if the item uuid is not currently in the db then add it
- $sql = "select * from v_menu_items ";
- $sql .= "where menu_uuid = :menu_uuid ";
- $parameters['menu_uuid'] = $this->menu_uuid;
- $menu_items = $this->database->select($sql, $parameters, 'all');
-
- //use the app array to restore the default menu
- if (is_array($apps)) {
- $x = 0;
- foreach ($apps as $row) {
- if (is_array($row['menu'])) {
- foreach ($row['menu'] as $menu) {
- //set the variables
- if (!empty($menu['title'][$this->menu_language])) {
- $menu_item_title = $menu['title'][$this->menu_language];
- }
- else {
- $menu_item_title = $menu['title']['en-us'];
- }
- $uuid = $menu['uuid'];
- $menu_item_uuid = $uuid_array[$menu['uuid']];
- $menu_item_parent_uuid = $uuid_array[$menu['parent_uuid']] ?? null;
- $menu_item_category = $menu['category'];
- $menu_item_icon = $menu['icon'] ?? null;
- $menu_item_icon_color = $menu['icon_color'] ?? null;
- $menu_item_path = $menu['path'];
- $menu_item_order = $menu['order'] ?? null;
- $menu_item_description = $menu['desc'] ?? null;
-
- //sanitize the menu link
- $menu_item_path = preg_replace('#[^a-zA-Z0-9_:\-\.\&\=\?\/]#', '', $menu_item_path);
-
- //check if the menu item exists and if it does set the row array
- $menu_item_exists = false;
- foreach ($menu_items as $item) {
- if ($item['uuid'] == $menu['uuid']) {
- $menu_item_exists = true;
- $row = $item;
- }
- }
-
- //item exists in the database
- if ($menu_item_exists) {
- $parent_menu_item_protected = 'false';
- //get parent_menu_item_protected
- foreach ($menu_items as $item) {
- if ($item['uuid'] == $menu['parent_uuid']) {
- $parent_menu_item_protected = $item['menu_item_protected'];
- }
- }
-
- //parent is not protected so the parent uuid needs to be updated
- if (is_uuid($menu_item_parent_uuid) && $menu_item_parent_uuid != $row['menu_item_parent_uuid'] && $parent_menu_item_protected != 'true') {
- $array['menu_items'][$x]['menu_item_uuid'] = $row['menu_item_uuid'];
- $array['menu_items'][$x]['menu_item_parent_uuid'] = $menu_item_parent_uuid;
- $x++;
- }
- }
-
- //item does not exist in the database
- if (!$menu_item_exists) {
- if ($menu_item_uuid != $menu_item_parent_uuid) {
- $array['menu_items'][$x]['menu_item_uuid'] = $menu_item_uuid;
- $array['menu_items'][$x]['menu_uuid'] = $this->menu_uuid;
- $array['menu_items'][$x]['uuid'] = $uuid;
- $array['menu_items'][$x]['menu_item_title'] = $menu_item_title;
- $array['menu_items'][$x]['menu_item_link'] = $menu_item_path;
- $array['menu_items'][$x]['menu_item_category'] = $menu_item_category;
- $array['menu_items'][$x]['menu_item_icon'] = $menu_item_icon;
- $array['menu_items'][$x]['menu_item_icon_color'] = $menu_item_icon_color;
- if (!empty($menu_item_order)) {
- $array['menu_items'][$x]['menu_item_order'] = $menu_item_order;
- }
- if (is_uuid($menu_item_parent_uuid)) {
- $array['menu_items'][$x]['menu_item_parent_uuid'] = $menu_item_parent_uuid;
- }
- $array['menu_items'][$x]['menu_item_description'] = $menu_item_description;
- $x++;
- }
- }
- unset($field, $parameters, $num_rows);
-
- //set the menu languages
- if (!$menu_item_exists && is_array($language->languages)) {
- foreach ($language->languages as $menu_language) {
- //set the menu item title
- if (!empty($menu["title"][$menu_language])) {
- $menu_item_title = $menu["title"][$menu_language];
- }
- else {
- $menu_item_title = $menu["title"]['en-us'];
- }
-
- //build insert array
- $array['menu_languages'][$x]['menu_language_uuid'] = uuid();
- $array['menu_languages'][$x]['menu_item_uuid'] = $menu_item_uuid;
- $array['menu_languages'][$x]['menu_uuid'] = $this->menu_uuid;
- $array['menu_languages'][$x]['menu_language'] = $menu_language;
- $array['menu_languages'][$x]['menu_item_title'] = $menu_item_title;
- $x++;
- }
- }
- }
- }
- }
- if (is_array($array) && @sizeof($array) != 0) {
- //grant temporary permissions
- $p = permissions::new();
- $p->add('menu_item_add', 'temp');
- $p->add('menu_language_add', 'temp');
- //execute insert
- $this->database->save($array);
- unset($array);
- //revoke temporary permissions
- $p->delete('menu_item_add', 'temp');
- $p->delete('menu_language_add', 'temp');
- }
- }
-
- //make sure the default user groups exist
- $group = new groups;
- $group->defaults();
-
- //get default global group_uuids
- $sql = "select group_uuid, group_name from v_groups ";
- $sql .= "where domain_uuid is null ";
- $result = $this->database->select($sql, null, 'all');
- if (is_array($result) && @sizeof($result) != 0) {
- foreach ($result as $row) {
- $group_uuids[$row['group_name']] = $row['group_uuid'];
- }
- }
- unset($sql, $result, $row);
-
- //if there are no groups listed in v_menu_item_groups under menu_item_uuid then add the default groups
- if (is_array($apps)) {
- $x = 0;
- foreach ($apps as $app) {
- if (is_array($apps)) {
- foreach ($app['menu'] as $sub_row) {
- if (isset($sub_row['groups'])) {
- foreach ($sub_row['groups'] as $group) {
- $sql = "select count(*) from v_menu_item_groups ";
- $sql .= "where menu_item_uuid = :menu_item_uuid ";
- $sql .= "and menu_uuid = :menu_uuid ";
- $sql .= "and group_name = :group_name ";
- $sql .= "and group_uuid = :group_uuid ";
- $parameters['menu_item_uuid'] = $uuid_array[$sub_row['uuid']];
- $parameters['menu_uuid'] = $this->menu_uuid;
- $parameters['group_name'] = $group;
- $parameters['group_uuid'] = $group_uuids[$group] ?? null;
- $num_rows = $this->database->select($sql, $parameters, 'column');
- if ($num_rows == 0) {
- //no menu item groups found, build insert array for defaults
- $array['menu_item_groups'][$x]['menu_item_group_uuid'] = uuid();
- $array['menu_item_groups'][$x]['menu_uuid'] = $this->menu_uuid;
- $array['menu_item_groups'][$x]['menu_item_uuid'] = $uuid_array[$sub_row['uuid']];
- $array['menu_item_groups'][$x]['group_name'] = $group;
- $array['menu_item_groups'][$x]['group_uuid'] = $group_uuids[$group] ?? null;
- $x++;
- }
- unset($sql, $parameters, $num_rows);
- }
- }
- }
- }
- }
-
- if (is_array($array) && @sizeof($array) != 0) {
- //grant temporary permissions
- $p = permissions::new();
- $p->add('menu_item_group_add', 'temp');
- //execute insert
- $this->database->save($array);
- unset($array);
- //revoke temporary permissions
- $p->delete('menu_item_group_add', 'temp');
- }
- }
-
- }
-
- /**
- * create the menu
- */
- public function build_html($menu_item_level = 0) {
-
- $menu_html_full = '';
-
- $menu_array = $this->menu_array();
-
- if (!isset($_SESSION['groups'])) {
- $_SESSION['groups'][0]['group_name'] = 'public';
- }
-
- if (is_array($menu_array)) {
- foreach($menu_array as $menu_field) {
- //set the variables
- $menu_item_link = $menu_field['menu_item_link'];
- $menu_item_category = $menu_field['menu_item_category'];
- $menu_items = $menu_field['menu_items'];
-
- //prepare the protected menus
- //$menu_item_title = ($menu_field['menu_item_protected'] == "true") ? $menu_field['menu_item_title'] : $menu_field['menu_language_title'];
- $menu_item_title = $menu_field['menu_language_title'];
-
- //prepare the menu_tags according to the category
- $menu_tags = '';
- switch ($menu_item_category) {
- case "internal":
- $menu_tags = "href='".PROJECT_PATH.$menu_item_link."'";
- break;
- case "external":
- if (substr($menu_item_link, 0,1) == "/") {
- $menu_item_link = PROJECT_PATH.$menu_item_link;
- }
- $menu_tags = "href='".$menu_item_link."' target='_blank'";
- break;
- case "email":
- $menu_tags = "href='mailto:".$menu_item_link."'";
- break;
- }
-
- if ($menu_item_level == 0) {
- $menu_html = "
\n";
- $menu_html .= "
\n";
- if (empty($this->username)) {
- $menu_html .= "
\n";
- }
- else {
- if ($menu_item_link == "/login.php" || $menu_item_link == "/users/signup.php") {
- //hide login and sign-up when the user is logged in
- }
- else {
- if (empty($menu_item_link)) {
- $menu_html .= "
\n";
+ }
+ }
- //user menu on body header when side menu
- //styles below are defined here to prevent caching (following a permission change, etc)
- $html .= "\n";
+ /**
+ * 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 = 'menu';
+ $this->table = 'menus';
- $html .= "
\n";
+ } else {
+ if ($menu_item_link == "/login.php" || $menu_item_link == "/users/signup.php") {
+ //hide login and sign-up when the user is logged in
+ } else {
+ if (empty($menu_item_link)) {
+ $menu_html .= "
\n";
+
+ //user menu on body header when side menu
+ //styles below are defined here to prevent caching (following a permission change, etc)
+ $html .= "\n";
+
+ $html .= "
\n";
+ /**
+ * Returns the data type of a column.
+ *
+ * This method retrieves the table info for the specified table name and then calls the
+ * data_type() method to get the data type of the specified column.
+ *
+ * @param string $table_name The name of the table.
+ * @param string $column_name The name of the column.
+ *
+ * @return mixed The data type of the column.
+ */
+ private function column_data_type($table_name, $column_name) {
+ $table_info = $this->table_info($table_name);
+ return $this->data_type($table_info, $column_name);
+ }
+
+ //database insert
+
+ /**
+ * Retrieves the data type of a column in the database.
+ *
+ * This method checks the data type based on the current database type and
+ * returns the corresponding value from the table_info array.
+ *
+ * @param array $table_info An array containing table information.
+ * @param string $column_name The name of the column to retrieve the data type for.
+ *
+ * @return mixed The data type of the specified column, or null if not found.
+ */
+ private function data_type($table_info, $column_name) {
+ if ($this->db_type == "sqlite") {
+ foreach ($table_info as $key => $row) {
+ if ($row['name'] == $column_name) {
+ return $row['type'];
}
- //list all tables
- $response .= "
\n";
- $response .= "
" . $text['label-table'] . "
\n";
- $response .= "
" . $text['label-exists'] . "
\n";
- $response .= "
" . $text['label-details'] . "
\n";
- $response .= "
\n";
- //build the html while looping through the app db array
- $sql = '';
- foreach ($this->applications as $app) {
- if (isset($app['db'])) {
- foreach ($app['db'] as $row) {
- if (is_array($row['table']['name'])) {
- $table_name = $row['table']['name']['text'];
- } else {
- $table_name = $row['table']['name'];
+ }
+ }
+ if ($this->db_type == "pgsql") {
+ foreach ($table_info as $key => $row) {
+ if ($row['column_name'] == $column_name) {
+ return $row['data_type'];
+ }
+ }
+ }
+ if ($this->db_type == "mysql") {
+ foreach ($table_info as $key => $row) {
+ if ($row['Field'] == $column_name) {
+ return $row['Type'];
+ }
+ }
+ }
+ }
+
+ //datatase schema
+
+ /**
+ * Inserts data from temporary tables into a specified database table.
+ *
+ * This method iterates through the provided applications, database definitions,
+ * and temporary tables to construct SQL INSERT statements. The constructed SQL
+ * statements are returned for execution.
+ *
+ * @param array $apps An array of application configurations.
+ * @param string $table The name of the target database table.
+ *
+ * @return string The constructed SQL INSERT statement as a string.
+ */
+ private function insert_into($apps, $table) {
+ foreach ($apps as $x => $app) {
+ foreach ($app['db'] as $y => $row) {
+ if ($row['table']['name'] == $table) {
+ $sql = "INSERT INTO " . $row['table']['name'] . " (";
+ $field_count = 0;
+ foreach ($row['fields'] as $field) {
+ if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
+ //skip this field
+ } else {
+ if ($field_count > 0) {
+ $sql .= ",";
}
- $response .= "
\n";
-
- //check if the table exists
- if ($row['exists'] == "true") {
- $response .= "
\n";
+ $field_count++;
}
}
- }
- //end the list of tables
- $response .= "
\n";
- $response .= " \n";
- }
-
- //loop line by line through all the lines of sql code
- $x = 0;
- if (empty($sql_update) && $format == "text") {
- $response .= " " . $text['label-schema'] ?? '' . ": " . $text['label-no_change'] . "\n";
- } else {
- if ($format == "text") {
- $response .= " " . $text['label-schema'] . "\n";
- }
- //$this->db->beginTransaction();
- $update_array = explode(";", $sql_update);
- if (is_array($update_array) && count($update_array)) {
- //drop views so that alter table statements complete
- $result = $this->database->views('drop');
-
- foreach ($update_array as $sql) {
- if (strlen(trim($sql))) {
- try {
- $this->database->execute(trim($sql), null);
- if ($format == "text") {
- $response .= " $sql;\n";
- }
- } catch (PDOException $error) {
- $response .= " error: " . $error->getMessage() . " sql: $sql\n";
- }
- }
- }
- }
- //$this->db->commit();
- $response .= "\n";
- unset($sql_update, $sql);
- }
-
- //refresh each postgresql subscription with its publication
- if ($this->db_type == "pgsql") {
- //get the list of postgresql subscriptions
- $sql = "select subname from pg_subscription; ";
- $pg_subscriptions = $this->database->select($sql, null, 'all');
- unset($sql, $parameters);
-
- //refresh each subscription publication
- foreach ($pg_subscriptions as $row) {
- $sql = "ALTER SUBSCRIPTION " . $row['subname'] . " REFRESH PUBLICATION;";
- $response .= $sql;
- $this->database->execute($sql);
+ $sql .= " FROM tmp_" . $table . ";\n";
+ return $sql;
}
}
-
- //create views so that alter table statements complete
- $this->database->views('create');
-
- //handle response
- return $response;
-
- } //end function
- }
+ }
+ } //end function
+}
//example use
//$schema = new schema();
diff --git a/resources/classes/service.php b/resources/classes/service.php
index ecbaab7e72..c69323b640 100644
--- a/resources/classes/service.php
+++ b/resources/classes/service.php
@@ -28,88 +28,69 @@
/**
* Service class
+ *
* @version 1.00
- * @author Tim Fry
+ * @author Tim Fry
*/
abstract class service {
const VERSION = "1.00";
-
- /**
- * Track the internal loop. It is recommended to use this variable to control the loop inside the run function. See the example
- * below the class for a more complete explanation
- * @var bool
- */
- protected $running;
-
/**
* current debugging level for output to syslog
+ *
* @var int Syslog level
*/
protected static $log_level = LOG_NOTICE;
-
/**
* config object
+ *
* @var config config object
*/
protected static $config;
-
/**
* Holds the parsed options from the command line
+ *
* @var array
*/
protected static $parsed_command_options;
-
- /**
- * Operating System process identification file
- * @var string
- */
- private static $pid_file = "";
-
/**
* Cli Options Array
+ *
* @var array
*/
protected static $available_command_options = [];
-
/**
* Holds the configuration file location
+ *
* @var string
*/
protected static $config_file = "";
-
/**
* Fork the service to it's own process ID
+ *
* @var bool
*/
protected static $daemon_mode = false;
-
/**
* Suppress the timestamp
* Used to suppress the timestamp in syslog
+ *
* @var bool
*/
protected static $show_timestamp_log = false;
-
/**
- * Child classes must provide a mechanism to reload settings
+ * Operating System process identification file
+ *
+ * @var string
*/
- abstract protected function reload_settings(): void;
-
+ private static $pid_file = "";
/**
- * Method to start the child class internal loop
+ * Track the internal loop. It is recommended to use this variable to control the loop inside the run function. See
+ * the example below the class for a more complete explanation
+ *
+ * @var bool
*/
- abstract public function run(): int;
-
- /**
- * Display version notice
- */
- abstract protected static function display_version(): void;
-
- /**
- * Called when the display_help_message is run in the base class for extra command line parameter explanation
- */
- abstract protected static function set_command_options();
+ protected $running;
/**
* Open a log when created.
@@ -123,27 +104,6 @@ abstract class service {
openlog('[php][' . self::class . ']', LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
}
- /**
- * Ensures the correct PID file is unlinked when this process terminates.
- *
- * This method is called automatically by PHP when an object's reference count reaches zero,
- * or when it's explicitly destroyed using unset(). It checks if the process is still running
- * and unlinks the corresponding PID file. Finally, it ensures that any open log connections
- * are properly closed before the script exits.
- *
- * @return void
- */
- public function __destruct() {
- //ensure we unlink the correct PID file if needed
- if (self::is_running()) {
- unlink(self::$pid_file);
- self::log("Initiating Shutdown...", LOG_NOTICE);
- $this->running = false;
- }
- //this should remain the last statement to execute before exit
- closelog();
- }
-
/**
* Shutdown the currently running process gracefully.
*/
@@ -162,66 +122,214 @@ abstract class service {
}
}
- // register signal handlers
- private function register_signal_handlers() {
- // Allow the calls to be made while the main loop is running
- pcntl_async_signals(true);
-
- // A signal listener to reload the service for any config changes in the database
- pcntl_signal(SIGUSR1, [$this, 'reload_settings']);
- pcntl_signal(SIGHUP, [$this, 'reload_settings']);
-
- // A signal listener to stop the service
- pcntl_signal(SIGUSR2, [self::class, 'shutdown']);
- pcntl_signal(SIGTERM, [self::class, 'shutdown']);
+ /**
+ * Checks if any service process is running.
+ *
+ * @return bool True if a service process is found, false otherwise
+ */
+ public static function is_any_running(): bool {
+ return self::get_service_pid() !== false;
}
/**
- * Extracts the short options from the cli options array and returns a string. The resulting string must
- * return a single string with all options in the string such as 'rxc:'.
- * This can be overridden by the child class.
- *
- * @return string
+ * Sends the shutdown signal to the service using a posix signal.
+ *
NOTE:
+ * The signal will not be received from the service if the
+ * command is sent from a user that has less privileges then
+ * the running service. For example, if the service is started
+ * by user root and then the command line option '-r' is given
+ * as user www-data, the service will not receive this signal
+ * because the OS will not allow the signal to be passed to a
+ * more privileged user due to security concerns. This would
+ * be the main reason why you must run a 'systemctl' or a
+ * 'service' command as root user. It is possible to start the
+ * service with user www-data and then the web UI would in fact
+ * be able to send the reload signal to the running service.
*/
- protected static function get_short_options(): string {
- return implode('' , array_map(function ($option) { return $option['short_option']; }, self::$available_command_options));
- }
-
- /**
- * Extracts the long options from the cli options array and returns an array. The resulting array must
- * return a single dimension array with an integer indexed key but does not have to be sequential order.
- * This can be overridden by the child class.
- *
- * @return array
- */
- protected static function get_long_options(): array {
- return array_map(function ($option) { return $option['long_option']; }, self::$available_command_options);
- }
-
- /**
- * Retrieves the callback functions associated with the cli options array.
- *
- * @param string $set_option The set option to match against available options
- *
- * @return array An array of callback functions that need to be called for the matched option
- */
- protected static function get_user_callbacks_from_available_options(string $set_option): array {
- //match the available option to the set option and return the callback function that needs to be called
- foreach(self::$available_command_options as $option) {
- $short_option = $option['short_option'] ?? '';
- if (str_ends_with($short_option, ':')) {
- $short_option = rtrim($short_option, ':');
- }
- $long_option = $option['long_option'] ?? '';
- if (str_ends_with($long_option, ':')) {
- $long_option = rtrim($long_option, ':');
- }
- if ($short_option === $set_option ||
- $long_option === $set_option) {
- return $option['functions'] ?? [$option['function']] ?? [];
+ public static function send_signal($posix_signal) {
+ $signal_name = "";
+ switch ($posix_signal) {
+ case 1: //SIGHUP
+ case 10: //SIGUSR1
+ $signal_name = "Reload";
+ break;
+ case 12: //SIGUSR2
+ case 15: //SIGTERM
+ $signal_name = "Shutdown";
+ break;
+ }
+ $pid = self::get_service_pid();
+ if ($pid === false) {
+ self::log("service not running", LOG_EMERG);
+ } else {
+ if (posix_kill((int)$pid, $posix_signal)) {
+ echo "Sent $signal_name\n";
+ } else {
+ $err = posix_strerror(posix_get_last_error());
+ echo "Failed to send $signal_name: $err\n";
}
}
- return [];
+ }
+
+ /**
+ * Write a standard copyright notice to the console
+ *
+ * @return void
+ */
+ public static function display_copyright(): void {
+ echo "FusionPBX\n";
+ echo "Version: MPL 1.1\n";
+ echo "\n";
+ echo "The contents of this file are subject to the Mozilla Public License Version\n";
+ echo "1.1 (the \"License\"); you may not use this file except in compliance with\n";
+ echo "the License. You may obtain a copy of the License at\n";
+ echo "http://www.mozilla.org/MPL/\n";
+ echo "\n";
+ echo "Software distributed under the License is distributed on an \"AS IS\" basis,\n";
+ echo "WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n";
+ echo "for the specific language governing rights and limitations under the\n";
+ echo "License.\n";
+ echo "\n";
+ echo "The Original Code is FusionPBX\n";
+ echo "\n";
+ echo "The Initial Developer of the Original Code is\n";
+ echo "Mark J Crane \n";
+ echo "Portions created by the Initial Developer are Copyright (C) 2008-2023\n";
+ echo "the Initial Developer. All Rights Reserved.\n";
+ echo "\n";
+ echo "Contributor(s):\n";
+ echo "Mark J Crane \n";
+ echo "Tim Fry \n";
+ echo "\n";
+ }
+
+ /**
+ * Sends a reload signal to running services, or exits if no service is running.
+ *
+ * @return void
+ */
+ public static function send_reload() {
+ if (self::is_any_running()) {
+ self::send_signal(10);
+ } else {
+ die("Service Not Started\n");
+ }
+ exit();
+ }
+
+ /**
+ * Set to foreground when started
+ */
+ public static function enable_daemon_mode() {
+ self::$daemon_mode = true;
+ self::$show_timestamp_log = false;
+ }
+
+ // register signal handlers
+
+ /**
+ * Set the configuration file to be used by FusionPBX.
+ *
+ * @param string $file The path to the configuration file (default: '/etc/fusionpbx/config.conf')
+ *
+ * @return void
+ */
+ public static function set_config_file(string $file = '/etc/fusionpbx/config.conf') {
+ if (empty(self::$config_file)) {
+ self::$config_file = $file;
+ }
+ self::$config = new config(self::$config_file);
+ }
+
+ /**
+ * Appends a command option to the list of available options.
+ *
+ * @param command_option $option The command option to append.
+ *
+ * @return int The index where the option was appended.
+ */
+ public static function append_command_option(command_option $option): int {
+ $index = count(self::$available_command_options);
+ self::$available_command_options[$index] = $option->to_array();
+ return $index;
+ }
+
+ /**
+ * Add a new command option to the available options list.
+ *
+ * @param string $short_option Short option (e.g., 'h' for '-h')
+ * @param string $long_option Long option (e.g., 'help' for '--help')
+ * @param string $description Brief description of the option
+ * @param string $short_description Short description of the short option (optional)
+ * @param string $long_description Long description of the long option (optional)
+ * @param mixed[] ...$callback Callback function(s) associated with this option
+ *
+ * @return int Index of the newly added command option in self::$available_command_options array
+ */
+ public static function add_command_option(string $short_option, string $long_option, string $description, string $short_description = '', string $long_description = '', ...$callback): int {
+ //use the option as the description if not filled in
+ if (empty($short_description)) {
+ $short_description = '-' . $short_option;
+ if (str_ends_with($short_option, ':')) {
+ $short_description .= " ";
+ }
+ }
+ if (empty($long_description)) {
+ $long_description = '-' . $long_option;
+ if (str_ends_with($long_option, ':')) {
+ $long_description .= " ";
+ }
+ }
+ $index = count(self::$available_command_options);
+ self::$available_command_options[$index]['short_option'] = $short_option;
+ self::$available_command_options[$index]['long_option'] = $long_option;
+ self::$available_command_options[$index]['description'] = $description;
+ self::$available_command_options[$index]['short_description'] = $short_description;
+ self::$available_command_options[$index]['long_description'] = $long_description;
+ self::$available_command_options[$index]['functions'] = $callback;
+ return $index;
+ }
+
+ /**
+ * Creates a new instance of the service class, initializing it and returning the object.
+ *
+ * @return self A new instance of the service class.
+ */
+ public static function create(): self {
+ //can only start from command line
+ defined('STDIN') or die('Unauthorized');
+
+ //parse the cli options and store them statically
+ self::parse_service_command_options();
+
+ //fork process
+ if (self::$daemon_mode) {
+ //force launching in a separate process
+ if ($pid = pcntl_fork()) {
+ exit;
+ }
+
+ if ($cid = pcntl_fork()) {
+ exit;
+ }
+ }
+
+ //create the config object if not already created
+ if (self::$config === null) {
+ self::$config = new config(self::$config_file);
+ }
+
+ //get the name of child object
+ $class = self::base_class_name();
+
+ //create the child object
+ $service = new $class();
+
+ //initialize the service
+ $service->init();
+
+ //return the initialized object
+ return $service;
}
/**
@@ -278,7 +386,7 @@ abstract class service {
//check for more than one function to be called is permitted
if (is_array($funcs)) {
//call each one
- foreach($funcs as $func) {
+ foreach ($funcs as $func) {
//use the best method to call the function
self::call_function($func, $option_value);
}
@@ -291,366 +399,22 @@ abstract class service {
}
//
- // Calls a function using the best suited PHP method
//
- private static function call_function($function, $args) {
- if ($function === 'exit') {
- //check for exit
- exit($args);
- } elseif ($function instanceof Closure || function_exists($function)) {
- //globally available function or closure
- $function($args);
- } else {
- static::$function($args);
- }
- }
-
- /**
- * Checks the file system for a pid file that matches the process ID from this running instance
- *
- * @return bool true if pid exists and false if not
- */
- public static function is_running(): bool {
- return posix_getpid() === self::get_service_pid();
- }
-
- /**
- * Checks if any service process is running.
- *
- * @return bool True if a service process is found, false otherwise
- */
- public static function is_any_running(): bool {
- return self::get_service_pid() !== false;
- }
-
- /**
- * Returns the process ID of the service if it exists and is running.
- *
- * @return int|false The process ID of the service, or false if it does not exist or is not running.
- */
- protected static function get_service_pid() {
- if (file_exists(static::get_pid_filename())) {
- $pid = file_get_contents(static::get_pid_filename());
- if (function_exists('posix_getsid')) {
- if (posix_getsid($pid) !== false) {
- //return the pid for reloading configuration
- return intval($pid);
- }
- } else {
- if (file_exists('/proc/' . $pid)) {
- //return the pid for reloading configuration
- return intval($pid);
- }
- }
- }
- return false;
- }
-
- /**
- * Create an operating system PID file removing any existing PID file
- */
- private function create_service_pid() {
- // Set the pid filename
- $basename = basename(self::$pid_file, '.pid');
- $pid = getmypid();
-
- // Remove the old pid file
- if (file_exists(self::$pid_file)) {
- if (is_writable(self::$pid_file)) {
- unlink(self::$pid_file);
- } else {
- throw new \RuntimeException("Unable to write to PID file " . self::$pid_file, 73); //Unix error code 73 - unable to write/create file
- }
- }
-
- // Show the details to the user
- self::log("Starting up...");
- self::log("Mode : " . (self::$daemon_mode ? "Daemon" : "Foreground"), LOG_INFO);
- self::log("Service : $basename", LOG_INFO);
- self::log("Process ID: $pid", LOG_INFO);
- self::log("PID File : " . self::$pid_file, LOG_INFO);
- self::log("Log level : " . self::log_level_to_string(self::$log_level), LOG_INFO);
- self::log("Timestamps: " . (self::$show_timestamp_log ? "Yes" : "No"), LOG_INFO);
-
- // Save the pid file
- $success = file_put_contents(self::$pid_file, $pid);
- if ($success === false) {
- throw new \RuntimeException("Failed writing to PID file " . self::$pid_file, 74); //Unix error code 74 - I/O error
- }
- }
-
- /**
- * Creates the service directory to store the PID
- *
- * @return void
- * @throws Exception thrown when the service directory is unable to be created
- */
- private function create_service_directory() {
- //make sure the /var/run/fusionpbx directory exists
- if (!file_exists('/var/run/fusionpbx')) {
- $result = mkdir('/var/run/fusionpbx', 0777, true);
- if (!$result) {
- throw new Exception('Failed to create /var/run/fusionpbx');
- }
- }
- }
-
- /**
- * Parses the debug level to an integer and stores it in the class for syslog use
- *
- * @param string $debug_level Debug level with any of the Linux system log levels
- *
- * @return void
- */
- protected static function set_debug_level(string $debug_level) {
- // Map user input log level to syslog constant
- switch ($debug_level) {
- case '0':
- case 'emergency':
- self::$log_level = LOG_EMERG; // Hardware failures
- break;
- case '1':
- case 'alert':
- self::$log_level = LOG_ALERT; // Loss of network connection or a condition that should be corrected immediately
- break;
- case '2':
- case 'critical':
- self::$log_level = LOG_CRIT; // Condition like low disk space
- break;
- case '3':
- case 'error':
- self::$log_level = LOG_ERR; // Database query failure, file not found
- break;
- case '4':
- case 'warning':
- self::$log_level = LOG_WARNING; // Deprecated function usage, approaching resource limits
- break;
- case '5':
- case 'notice':
- self::$log_level = LOG_NOTICE; // Normal conditions
- break;
- case '6':
- case 'info':
- self::$log_level = LOG_INFO; // Informational
- break;
- case '7':
- case 'debug':
- self::$log_level = LOG_DEBUG; // Debugging
- break;
- default:
- self::$log_level = LOG_NOTICE; // Default to NOTICE if invalid level
- }
-
- // When we are using LOG_DEBUG there is a high chance we are logging to the console
- // directly without systemctl so enable the timestamps by default
- if (self::$log_level === LOG_DEBUG && !self::$daemon_mode) {
- self::show_timestamp();
- }
- }
-
- /**
- * Converts a log level integer to its corresponding string representation.
- *
- * @param int $level The log level as an integer, defaults to LOG_NOTICE (5).
- *
- * @return string The log level as a string.
- */
- private static function log_level_to_string(int $level = LOG_NOTICE): string {
- switch ($level){
- case 0:
- return 'EMERGENCY';
- case 1:
- return 'ALERT';
- case 2:
- return 'CRITICAL';
- case 3:
- return 'ERROR';
- case 4:
- return 'WARNING';
- case 5:
- return 'NOTICE';
- case 6:
- return 'INFO';
- case 7:
- return 'DEBUG';
- default:
- return 'INFO';
- }
- }
-
- /**
- * Logs the current and peak memory usage of the application at the INFO level.
- *
- * @return void
- */
- protected static function show_mem_usage() {
- //current memory
- $memory_usage = memory_get_usage();
- //peak memory
- $memory_peak = memory_get_peak_usage();
- self::log('Current memory: ' . round($memory_usage / 1024) . " KB", LOG_INFO);
- self::log('Peak memory: ' . round($memory_peak / 1024) . " KB", LOG_INFO);
- }
-
- /**
- * Logs to the system log or console when running in foreground
- *
- * @param string $message Message to display in the system log or console when running in foreground
- * @param int $level (Optional) Level to use for logging to the console or daemon. Default value is LOG_NOTICE
- *
- * @return void
- */
- protected static function log(string $message, int $level = LOG_NOTICE) {
- // Check if we need to show the message
- if ($level <= self::$log_level) {
- // When not in daemon mode we log to console directly
- if (!self::$daemon_mode) {
- $level_as_string = self::log_level_to_string($level);
- if (!self::$show_timestamp_log) {
- echo "[$level_as_string] $message\n";
- } else {
- $time = date('Y-m-d H:i:s');
- echo "[$time][$level_as_string] $message\n";
- }
- } else {
- // Log the message to syslog
- syslog($level, 'fusionpbx[' . posix_getpid() . ']: ['.static::class.'] '.$message);
- }
- }
- }
-
- /**
- * Returns a file safe class name with \ from namespaces converted to _
- * @return string file safe name
- */
- protected static function base_file_name(): string {
- return str_replace('\\', "_", static::class);
- }
-
- /**
- * Returns only the name of the class without namespace
- * @return string base class name
- */
- protected static function base_class_name(): string {
- $class_and_namespace = explode('\\', static::class);
- return array_pop($class_and_namespace);
- }
-
- /**
- * Write a standard copyright notice to the console
- *
- * @return void
- */
- public static function display_copyright(): void {
- echo "FusionPBX\n";
- echo "Version: MPL 1.1\n";
- echo "\n";
- echo "The contents of this file are subject to the Mozilla Public License Version\n";
- echo "1.1 (the \"License\"); you may not use this file except in compliance with\n";
- echo "the License. You may obtain a copy of the License at\n";
- echo "http://www.mozilla.org/MPL/\n";
- echo "\n";
- echo "Software distributed under the License is distributed on an \"AS IS\" basis,\n";
- echo "WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n";
- echo "for the specific language governing rights and limitations under the\n";
- echo "License.\n";
- echo "\n";
- echo "The Original Code is FusionPBX\n";
- echo "\n";
- echo "The Initial Developer of the Original Code is\n";
- echo "Mark J Crane \n";
- echo "Portions created by the Initial Developer are Copyright (C) 2008-2023\n";
- echo "the Initial Developer. All Rights Reserved.\n";
- echo "\n";
- echo "Contributor(s):\n";
- echo "Mark J Crane \n";
- echo "Tim Fry \n";
- echo "\n";
- }
-
- /**
- * Sends the shutdown signal to the service using a posix signal.
- *
NOTE:
- * The signal will not be received from the service if the
- * command is sent from a user that has less privileges then
- * the running service. For example, if the service is started
- * by user root and then the command line option '-r' is given
- * as user www-data, the service will not receive this signal
- * because the OS will not allow the signal to be passed to a
- * more privileged user due to security concerns. This would
- * be the main reason why you must run a 'systemctl' or a
- * 'service' command as root user. It is possible to start the
- * service with user www-data and then the web UI would in fact
- * be able to send the reload signal to the running service.