Documentation, format class, no modification. (#7629)

This commit is contained in:
frytimo
2025-11-19 12:48:36 -04:00
committed by GitHub
parent 0ea256fce8
commit 34821bed7e
36 changed files with 12982 additions and 11551 deletions

View File

@@ -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');
?>

View File

@@ -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, "<?php\n return " . $classes_array . ";\n");
if ($class_result === false) {
//file failed to save - send error to syslog when debugging
$error_array = error_get_last();
self::log(LOG_WARNING, $error_array['message'] ?? '');
}
//export the interfaces array using PHP engine
$interfaces_array = var_export($this->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, "<?php\n return " . $interfaces_array . ";\n");
if ($interface_result === false) {
//file failed to save - send error to syslog when debugging
$error_array = error_get_last();
self::log(LOG_WARNING, $error_array['message'] ?? '');
}
$result = ($class_result && $interface_result);
return $result;
}
public function load_cache(): bool {
$this->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, "<?php\n return " . $classes_array . ";\n");
if ($class_result === false) {
//file failed to save - send error to syslog when debugging
$error_array = error_get_last();
self::log(LOG_WARNING, $error_array['message'] ?? '');
}
//export the interfaces array using PHP engine
$interfaces_array = var_export($this->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, "<?php\n return " . $interfaces_array . ";\n");
if ($interface_result === false) {
//file failed to save - send error to syslog when debugging
$error_array = error_get_last();
self::log(LOG_WARNING, $error_array['message'] ?? '');
}
$result = ($class_result && $interface_result);
return $result;
}
/**
* Returns a list of classes implementing the interface
* @param string $interface_name
* @return array
* Logs a message at the specified level
*
* @param int $level The log level (e.g. E_ERROR)
* @param string $message The log message
*/
public function get_interface_list(string $interface_name): array {
//make sure we can return values
if (empty($this->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;
}
}

View File

@@ -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;
}
}
?>

View File

@@ -25,123 +25,144 @@
Mark J Crane <markjcrane@fusionpbx.com>
*/
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 = "<button ";
$button .= "type='".(!empty($array['type']) ? $array['type'] : 'button')."' ";
$button .= !empty($array['name']) ? "name=".self::quote($array['name'])." " : null;
$button .= !empty($array['value']) ? "value=".self::quote($array['value'])." " : null;
$button .= !empty($array['id']) ? "id='".$array['id']."' " : null;
$button .= !empty($array['label']) ? "alt=".self::quote($array['label'])." " : (!empty($array['title']) ? "alt=".self::quote($array['title'])." " : null);
if ($button_icons == 'only' || $button_icons == 'auto' || $array['title']) {
if (!empty($array['title']) || !empty($array['label'])) {
$button .= "title=".(!empty($array['title']) ? self::quote($array['title']) : self::quote($array['label']))." ";
$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]);
}
}
$button .= !empty($array['onclick']) ? "onclick=".self::quote($array['onclick'])." " : null;
$button .= !empty($array['onmouseover']) ? "onmouseenter=".self::quote($array['onmouseover'])." " : null;
$button .= !empty($array['onmouseout']) ? "onmouseleave=".self::quote($array['onmouseout'])." " : null;
//detect class addition (using + prefix)
$button_class = !empty($array['class']) && substr($array['class'],0,1) == '+' ? 'default '.substr($array['class'], 1) : $array['class'] ?? '';
$button .= "class='btn btn-".(!empty($button_class) ? $button_class : 'default')." ".(isset($array['disabled']) && $array['disabled'] ? 'disabled' : null)."' ";
//ensure margin* styles are not applied to the button element when a link is defined
if (!empty($array['style']) && is_array($array['style']) && @sizeof($array['style']) != 0) {
$styles = '';
foreach ($array['style'] as $property => $value) {
if (empty($array['link']) || !substr_count($property, 'margin')) {
$styles .= $property.': '.$value.'; ';
}
}
$button .= $styles ? "style=".self::quote($styles)." " : null;
unset($styles);
}
$button .= isset($array['disabled']) && $array['disabled'] ? "disabled='disabled' " : null;
$button .= ">";
//icon
if (!empty($array['icon']) && (
$button_icons == 'only' ||
$button_icons == 'always' ||
$button_icons == 'auto' ||
!$array['label']
)) {
$icon_class = is_array($array['icon']) ? $array['icon']['text'] : $array['icon'];
$button .= "<span class='".(substr($icon_class, 0, 3) != 'fa-' ? 'fa-solid fa-' : null).$icon_class." fa-fw'></span>";
}
//label
if (!empty($array['label']) && (
$button_icons != 'only' ||
!$array['icon'] ||
$array['class'] == 'link'
)) {
if (!empty($array['icon']) && $button_icons != 'always' && $button_icons != 'never' && isset($array['collapse']) && $array['collapse'] !== false) {
if ($array['collapse'] != '') {
$collapse_class = $array['collapse'];
}
else if (self::$collapse !== false) {
$collapse_class = self::$collapse;
}
}
$pad_class = !empty($array['icon']) ? 'pad' : null;
$button .= "<span class='button-label ".($collapse_class ?? '')." ".$pad_class."'>".$array['label']."</span>";
}
//button: close
$button .= "</button>";
//link
if (!empty($array['link'])) {
$anchor = "<a ";
$anchor .= "href='" . self::escape_href($array['link']) . "' ";
$anchor .= "target='".(!empty($array['target']) ? $array['target'] : '_self')."' ";
//ensure only margin* styles are applied to the anchor element
if (!empty($array['style']) && is_array($array['style']) && @sizeof($array['style']) != 0) {
$styles = '';
foreach ($array['style'] as $property => $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."</a>";
}
return $button;
}
$array['style'] = $styles;
unset($styles);
}
private static function quote($value) {
return substr_count($value, "'") ? '"'.$value.'"' : "'".$value."'";
//button: open
$button = "<button ";
$button .= "type='" . (!empty($array['type']) ? $array['type'] : 'button') . "' ";
$button .= !empty($array['name']) ? "name=" . self::quote($array['name']) . " " : null;
$button .= !empty($array['value']) ? "value=" . self::quote($array['value']) . " " : null;
$button .= !empty($array['id']) ? "id='" . $array['id'] . "' " : null;
$button .= !empty($array['label']) ? "alt=" . self::quote($array['label']) . " " : (!empty($array['title']) ? "alt=" . self::quote($array['title']) . " " : null);
if ($button_icons == 'only' || $button_icons == 'auto' || $array['title']) {
if (!empty($array['title']) || !empty($array['label'])) {
$button .= "title=" . (!empty($array['title']) ? self::quote($array['title']) : self::quote($array['label'])) . " ";
}
}
private static function escape_href(string $url): string {
// clear whitespace
$url = trim($url);
return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
$button .= !empty($array['onclick']) ? "onclick=" . self::quote($array['onclick']) . " " : null;
$button .= !empty($array['onmouseover']) ? "onmouseenter=" . self::quote($array['onmouseover']) . " " : null;
$button .= !empty($array['onmouseout']) ? "onmouseleave=" . self::quote($array['onmouseout']) . " " : null;
//detect class addition (using + prefix)
$button_class = !empty($array['class']) && substr($array['class'], 0, 1) == '+' ? 'default ' . substr($array['class'], 1) : $array['class'] ?? '';
$button .= "class='btn btn-" . (!empty($button_class) ? $button_class : 'default') . " " . (isset($array['disabled']) && $array['disabled'] ? 'disabled' : null) . "' ";
//ensure margin* styles are not applied to the button element when a link is defined
if (!empty($array['style']) && is_array($array['style']) && @sizeof($array['style']) != 0) {
$styles = '';
foreach ($array['style'] as $property => $value) {
if (empty($array['link']) || !substr_count($property, 'margin')) {
$styles .= $property . ': ' . $value . '; ';
}
}
$button .= $styles ? "style=" . self::quote($styles) . " " : null;
unset($styles);
}
$button .= isset($array['disabled']) && $array['disabled'] ? "disabled='disabled' " : null;
$button .= ">";
//icon
if (!empty($array['icon']) && (
$button_icons == 'only' ||
$button_icons == 'always' ||
$button_icons == 'auto' ||
!$array['label']
)) {
$icon_class = is_array($array['icon']) ? $array['icon']['text'] : $array['icon'];
$button .= "<span class='" . (substr($icon_class, 0, 3) != 'fa-' ? 'fa-solid fa-' : null) . $icon_class . " fa-fw'></span>";
}
//label
if (!empty($array['label']) && (
$button_icons != 'only' ||
!$array['icon'] ||
$array['class'] == 'link'
)) {
if (!empty($array['icon']) && $button_icons != 'always' && $button_icons != 'never' && isset($array['collapse']) && $array['collapse'] !== false) {
if ($array['collapse'] != '') {
$collapse_class = $array['collapse'];
} elseif (self::$collapse !== false) {
$collapse_class = self::$collapse;
}
}
$pad_class = !empty($array['icon']) ? 'pad' : null;
$button .= "<span class='button-label " . ($collapse_class ?? '') . " " . $pad_class . "'>" . $array['label'] . "</span>";
}
//button: close
$button .= "</button>";
//link
if (!empty($array['link'])) {
$anchor = "<a ";
$anchor .= "href='" . self::escape_href($array['link']) . "' ";
$anchor .= "target='" . (!empty($array['target']) ? $array['target'] : '_self') . "' ";
//ensure only margin* styles are applied to the anchor element
if (!empty($array['style']) && is_array($array['style']) && @sizeof($array['style']) != 0) {
$styles = '';
foreach ($array['style'] as $property => $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 . "</a>";
}
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

View File

@@ -1,6 +1,5 @@
<?php
/**
* Provides an abstracted cache
*/
@@ -11,7 +10,11 @@ class cache {
private $method;
/**
* Called when the object is created
* Initializes the cache object with default settings if none are provided.
*
* @param settings|null $settings The settings to use for initialization. Defaults to null.
*
* @return void
*/
public function __construct(settings $settings = null) {
//set defaults
@@ -29,217 +32,236 @@ class cache {
$this->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;
}
}
?>

View File

@@ -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 "<img src=\"data:image/png;base64, ".$image_base64."\" />\n";
*/
?>

View File

@@ -28,6 +28,7 @@
/**
* Container object for creating command line options when creating a service
*
* @author Tim Fry <tim@fusionpbx.com>
*/
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

View File

@@ -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.
* <p>This will allow using config object with the syntax of:<br>
* $config = new config();<br>
* $db_type = $config->db_type;<br></p>
* <p>Note:<br>
* The <i>InvalidArgumentException</i> is thrown if there is no such variable accessed such as:<br>
* $config = new config();<br>
* $db_function = $config->db_function();
* </p>
* <p>This is ensure that any invalid code is detected and fixed.</p>
* @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.
* <p>This will allow using config object with the syntax of:<br>
* $config = new config();<br>
* $db_type = $config->db_type;<br></p>
* <p>Note:<br>
* The <i>InvalidArgumentException</i> is thrown if there is no such variable accessed such as:<br>
* $config = new config();<br>
* $db_function = $config->db_function();
* </p>
* <p>This is ensure that any invalid code is detected and fixed.</p>
*
* @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;
}
}
/*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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
* <p>Multi-line commands can be sent when separated by '\n'</p>
*
* @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
* <p>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</p>
* @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
* <p>Multi-line commands can be sent when separated by '\n'</p>
* @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'));
?>

View File

@@ -1,58 +1,122 @@
<?php
/**
* cache class provides an abstracted cache
* file class provides an abstracted cache
*/
class file {
/**
* variables
*/
*/
public $recursive;
public $files;
/**
* 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(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'] ?? '';
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);
*/
?>

View File

@@ -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;
}
}

View File

@@ -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);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,16 @@
* @author Tim Fry <tim@fusionpbx.com>
*/
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);
}
}

View File

@@ -1,165 +1,269 @@
<?php
/**
* Logging class:
* - constructor requires the full file name and path for the log file. if it
* does not exist php will automatically try and create it. The log file will
* remain open for the life cycle of the object to improve performance.
* - message is written with the following format: [d/M/Y:H:i:s] (script name) message.
* - log file is closed when the object is destroyed.
*/
class logging {
// declare log file and file pointer as private properties
private $fp;
private $debug_func;
private $debug_line;
private $debug_file;
private $debug_class;
/**
* Logging class:
* - constructor requires the full file name and path for the log file. if it
* does not exist php will automatically try and create it. The log file will
* remain open for the life cycle of the object to improve performance.
* - message is written with the following format: [d/M/Y:H:i:s] (script name) message.
* - log file is closed when the object is destroyed.
* Initializes a new instance of this class.
*
* Opens a file in append mode and sets it as the output stream for subsequent operations.
*
* @param string $filename_and_path The path to the file to be opened.
*
* @throws Exception If there is an error opening the file.
*/
class logging {
public function __construct(string $filename_and_path) {
//init values
$this->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");
*/
// 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");
*/

File diff suppressed because it is too large Load Diff

View File

@@ -25,48 +25,70 @@
Matthew Vale <github@mafoo.org>
*/
class message {
class message {
static function add($message, $mood = null, $delay = null) {
//set mood and delay
$mood = $mood ?: 'positive';
$delay = $delay ?: (1000 * (float) $_SESSION['theme']['message_delay']['text']);
//ignore duplicate messages
if (isset($_SESSION["messages"]) && !empty($_SESSION["messages"][$mood]['message'])) {
if (!in_array($message, $_SESSION["messages"][$mood]['message'])) {
$_SESSION["messages"][$mood]['message'][] = $message;
$_SESSION["messages"][$mood]['delay'][] = $delay;
}
}
else {
$_SESSION["messages"][$mood]['message'][] = $message;
$_SESSION["messages"][$mood]['delay'][] = $delay;
}
}
/**
* Returns the total number of messages in the session.
*
* @return int The number of messages, or 0 if no messages are present in the session.
*/
static function count() {
return isset($_SESSION["messages"]) && is_array($_SESSION["messages"]) ? sizeof($_SESSION["messages"]) : 0;
}
static function count() {
return isset($_SESSION["messages"]) && is_array($_SESSION["messages"]) ? sizeof($_SESSION["messages"]) : 0;
}
static function html($clear_messages = true, $spacer = "") {
$html = "{$spacer}//render the messages\n";
$spacer .="\t";
if (isset($_SESSION['message']) || isset($_SESSION['messages'])) {
if (!empty($_SESSION['message']) && !is_array($_SESSION['message'])) {
self::add($_SESSION['message'], $_SESSION['message_mood'] ?? null, $_SESSION['message_delay'] ?? null);
unset($_SESSION['message'], $_SESSION['message_mood'], $_SESSION['message_delay']);
}
if (!empty($_SESSION['messages']) && is_array($_SESSION['messages']) && @sizeof($_SESSION['messages']) != 0) {
foreach ($_SESSION['messages'] as $message_mood => $message) {
$message_text = str_replace(array("\r\n", "\n", "\r"),'\\n',addslashes(join('<br/>', $message['message'])));
$message_delay = array_sum($message['delay'])/count($message['delay']);
$html .= "{$spacer}display_message('$message_text', '$message_mood', '$message_delay');\n";
}
/**
* Renders session messages into HTML.
*
* @param bool $clear_messages Whether to clear the session 'messages' array after rendering. Defaults to true.
* @param string $spacer The indentation spacer for the generated HTML code.
*
* @return string The rendered HTML message display code.
*/
static function html($clear_messages = true, $spacer = "") {
$html = "{$spacer}//render the messages\n";
$spacer .= "\t";
if (isset($_SESSION['message']) || isset($_SESSION['messages'])) {
if (!empty($_SESSION['message']) && !is_array($_SESSION['message'])) {
self::add($_SESSION['message'], $_SESSION['message_mood'] ?? null, $_SESSION['message_delay'] ?? null);
unset($_SESSION['message'], $_SESSION['message_mood'], $_SESSION['message_delay']);
}
if (!empty($_SESSION['messages']) && is_array($_SESSION['messages']) && @sizeof($_SESSION['messages']) != 0) {
foreach ($_SESSION['messages'] as $message_mood => $message) {
$message_text = str_replace(["\r\n", "\n", "\r"], '\\n', addslashes(join('<br/>', $message['message'])));
$message_delay = array_sum($message['delay']) / count($message['delay']);
$html .= "{$spacer}display_message('$message_text', '$message_mood', '$message_delay');\n";
}
}
if ($clear_messages) {
unset($_SESSION['messages']);
}
if ($clear_messages) {
unset($_SESSION['messages']);
}
return $html;
}
/**
* Adds a message to the session messages array.
*
* @param string $message The message to add.
* @param string|null $mood The mood of the message. Defaults to 'positive'.
* @param int|null $delay The delay before displaying the message. Defaults to the theme's default text
* message delay in milliseconds.
*
* @return void
*/
static function add($message, $mood = null, $delay = null) {
//set mood and delay
$mood = $mood ?: 'positive';
$delay = $delay ?: (1000 * (float)$_SESSION['theme']['message_delay']['text']);
//ignore duplicate messages
if (isset($_SESSION["messages"]) && !empty($_SESSION["messages"][$mood]['message'])) {
if (!in_array($message, $_SESSION["messages"][$mood]['message'])) {
$_SESSION["messages"][$mood]['message'][] = $message;
$_SESSION["messages"][$mood]['delay'][] = $delay;
}
return $html;
} else {
$_SESSION["messages"][$mood]['message'][] = $message;
$_SESSION["messages"][$mood]['delay'][] = $delay;
}
}
}

View File

@@ -25,52 +25,70 @@
Mark J Crane <markjcrane@fusionpbx.com>
*/
class modal {
class modal {
static function create($array) {
/**
* Creates a modal window.
*
* @param array $array Array containing the modal's properties.
* The following keys are supported:
* - id: ID of the modal (optional).
* - type: Type of the modal (optional, one of 'copy', 'toggle',
* 'delete' or 'unassign'). If not specified, a general
* modal will be created. Defaults to 'general'.
* - title: Title of the modal (optional). If not specified,
* a default title will be used based on the type.
* - message: Message of the modal (optional).
* - actions: Actions of the modal (optional).
* - onclose: Function to call when the modal is closed
* (optional).
*
* @return string HTML string representing the modal window.
*/
static function create($array) {
//define as global
global $settings;
//define as global
global $settings;
//add multi-lingual support
$language = new text;
$text = $language->get();
//add multi-lingual support
$language = new text;
$text = $language->get();
$modal = "<div id='".(!empty($array['id']) ? $array['id'] : 'modal')."' class='modal-window'>\n";
$modal .= " <div>\n";
$modal .= " <span title=\"".$text['button-close']."\" class='modal-close' onclick=\"modal_close(); ".($array['onclose'] ?? '')."\">&times</span>\n";
if (!empty($array['type'])) {
//determine type
switch ($array['type']) {
case 'copy':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-copy'];
break;
case 'toggle':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-toggle'];
break;
case 'delete':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-delete'];
break;
case 'unassign':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-unassign'];
default: //general
$array['title'] = !empty($array['title']) ? $array['title'] : $text['modal_title-confirmation'];
}
//prefix cancel button to action
$array['actions'] = button::create(['type'=>'button','label'=>$text['button-cancel'],'icon'=>$settings->get('theme', 'button_icon_cancel'),'collapse'=>'never','onclick'=>'modal_close(); '.($array['onclose'] ?? '')]).$array['actions'];
$modal = "<div id='" . (!empty($array['id']) ? $array['id'] : 'modal') . "' class='modal-window'>\n";
$modal .= " <div>\n";
$modal .= " <span title=\"" . $text['button-close'] . "\" class='modal-close' onclick=\"modal_close(); " . ($array['onclose'] ?? '') . "\">&times</span>\n";
if (!empty($array['type'])) {
//determine type
switch ($array['type']) {
case 'copy':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-copy'];
break;
case 'toggle':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-toggle'];
break;
case 'delete':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-delete'];
break;
case 'unassign':
$array['title'] = $text['modal_title-confirmation'];
$array['message'] = $text['confirm-unassign'];
default: //general
$array['title'] = !empty($array['title']) ? $array['title'] : $text['modal_title-confirmation'];
}
$modal .= !empty($array['title']) ? " <span class='modal-title'>".$array['title']."</span>\n" : null;
$modal .= !empty($array['message']) ? " <span class='modal-message'>".$array['message']."</span>\n" : null;
$modal .= !empty($array['actions']) ? " <span class='modal-actions'>".$array['actions']."</span>\n" : null;
$modal .= " </div>\n";
$modal .= "</div>";
return $modal;
//prefix cancel button to action
$array['actions'] = button::create(['type' => 'button', 'label' => $text['button-cancel'], 'icon' => $settings->get('theme', 'button_icon_cancel'), 'collapse' => 'never', 'onclick' => 'modal_close(); ' . ($array['onclose'] ?? '')]) . $array['actions'];
}
$modal .= !empty($array['title']) ? " <span class='modal-title'>" . $array['title'] . "</span>\n" : null;
$modal .= !empty($array['message']) ? " <span class='modal-message'>" . $array['message'] . "</span>\n" : null;
$modal .= !empty($array['actions']) ? " <span class='modal-actions'>" . $array['actions'] . "</span>\n" : null;
$modal .= " </div>\n";
$modal .= "</div>";
return $modal;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -26,15 +26,23 @@
*/
class permissions {
private static $permission;
private $database;
private $domain_uuid;
private $user_uuid;
private $groups;
private $permissions;
private static $permission;
/**
* called when the object is created
* Constructor.
*
* Initializes this object with a database connection, domain UUID, and user UUID.
*
* @param Database|null $database Database connection. If null, a new database connection will be created.
* @param string|null $domain_uuid Domain UUID. If null, the value from the session will be used.
* @param string|null $user_uuid User UUID. If null, the value from the session will be used.
*
* @return void
*/
public function __construct($database = null, $domain_uuid = null, $user_uuid = null) {
@@ -45,32 +53,28 @@ class permissions {
//handle the database object
if (isset($database)) {
$this->database = $database;
}
else {
} else {
$this->database = database::new();
}
//set the domain_uuid
if (!empty($domain_uuid) && is_uuid($domain_uuid)) {
$this->domain_uuid = $domain_uuid;
}
elseif (isset($_SESSION['domain_uuid']) && is_uuid($_SESSION['domain_uuid'])) {
} elseif (isset($_SESSION['domain_uuid']) && is_uuid($_SESSION['domain_uuid'])) {
$this->domain_uuid = $_SESSION['domain_uuid'];
}
//set the user_uuid
if (!empty($user_uuid) && is_uuid($user_uuid)) {
$this->user_uuid = $user_uuid;
}
elseif (isset($_SESSION['user_uuid']) && is_uuid($_SESSION['user_uuid'])) {
} elseif (isset($_SESSION['user_uuid']) && is_uuid($_SESSION['user_uuid'])) {
$this->user_uuid = $_SESSION['user_uuid'];
}
//get the permissions
if (isset($_SESSION['permissions'])) {
$this->permissions = $_SESSION['permissions'];
}
else {
} else {
//create the groups object
$groups = new groups($this->database, $this->domain_uuid, $this->user_uuid);
$this->groups = $groups->assigned();
@@ -83,15 +87,92 @@ class permissions {
}
/**
* get the array of permissions
* A singleton pattern for either creating a new object or the existing object.
*
* Initializes this object with a database connection, domain UUID, and user UUID.
*
* @param Database|null $database Database connection. If null, a new database connection will be created.
* @param string|null $domain_uuid Domain UUID. If null, the value from the session will be used.
* @param string|null $user_uuid User UUID. If null, the value from the session will be used.
*
* @return self
*/
public static function new($database = null, $domain_uuid = null, $user_uuid = null) {
if (self::$permission === null) {
self::$permission = new permissions($database, $domain_uuid, $user_uuid);
}
return self::$permission;
}
/**
* Method to retrieve permissions assigned to the user through their groups.
*
* Retrieves the list of group names associated with the user's assigned groups,
* and then uses these group names to query for distinct permission names that are
* assigned to these groups. The resulting list of permission names is stored in
* this object's 'permissions' array.
*
* @return void
*/
private function assigned() {
//define the array
$permissions = [];
$parameter_names = [];
//return empty array if there are no groups
if (empty($this->groups)) {
return [];
}
//prepare the parameters
$x = 0;
foreach ($this->groups as $field) {
if (!empty($field['group_name'])) {
$parameter_names[] = ":group_name_" . $x;
$parameters['group_name_' . $x] = $field['group_name'];
$x++;
}
}
//get the permissions assigned to the user through the assigned groups
$sql = "select distinct(permission_name) from v_group_permissions ";
$sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) ";
$sql .= "and group_name in (" . implode(", ", $parameter_names) . ") \n";
$sql .= "and permission_assigned = 'true' ";
$parameters['domain_uuid'] = $this->domain_uuid;
$group_permissions = $this->database->select($sql, $parameters, 'all');
//format the permission array
foreach ($group_permissions as $row) {
$permissions[$row['permission_name']] = 1;
}
//save permissions to this object
$this->permissions = $permissions;
}
/**
* Returns an array of permissions assigned to this user.
*
* The list of permissions is populated from the session or retrieved from the database based on
* the domain UUID and user UUID associated with this object.
*
* @return array An array of permission identifiers (e.g. 'create_user', 'edit_group', etc.)
*/
public function get_permissions() {
return $this->permissions;
}
/**
* Add the permission
* @var string $permission
* Adds a permission to this object.
*
* If the specified permission does not already exist, it will be added to the permissions array with the provided
* type.
*
* @param string $permission Permission to add.
* @param mixed $type Type of the permission.
*
* @return void
*/
public function add($permission, $type) {
//add the permission if it is not in array
@@ -101,27 +182,13 @@ class permissions {
}
/**
* Remove the permission
* @var string $permission
*/
public function delete($permission, $type) {
if ($this->exists($permission) && !empty($this->permissions[$permission])) {
if ($type === "temp") {
if ($this->permissions[$permission] === "temp") {
unset($this->permissions[$permission]);
}
}
else {
if ($this->permissions[$permission] !== "temp") {
unset($this->permissions[$permission]);
}
}
}
}
/**
* Check to see if the permission exists
* @var string $permission
* Checks if a permission exists.
*
* Returns true if the permission is assigned to the user, or if this method is called from the command line.
*
* @param string $permission_name Name of the permission to check for existence.
*
* @return bool True if the permission exists, false otherwise.
*/
public function exists($permission_name) {
@@ -139,48 +206,33 @@ class permissions {
}
/**
* get the assigned permissions
* @var array $groups
* Deletes a permission.
*
* If the permission exists and is not temporary, it will be removed from the permissions array.
*
* @param string $permission The name of the permission to delete.
* @param string $type The type of permission (e.g. "temp", "permanent").
*
* @return void
*/
private function assigned() {
//define the array
$permissions = [];
$parameter_names = [];
//return empty array if there are no groups
if (empty($this->groups)) {
return [];
}
//prepare the parameters
$x = 0;
foreach ($this->groups as $field) {
if (!empty($field['group_name'])) {
$parameter_names[] = ":group_name_".$x;
$parameters['group_name_'.$x] = $field['group_name'];
$x++;
public function delete($permission, $type) {
if ($this->exists($permission) && !empty($this->permissions[$permission])) {
if ($type === "temp") {
if ($this->permissions[$permission] === "temp") {
unset($this->permissions[$permission]);
}
} else {
if ($this->permissions[$permission] !== "temp") {
unset($this->permissions[$permission]);
}
}
}
//get the permissions assigned to the user through the assigned groups
$sql = "select distinct(permission_name) from v_group_permissions ";
$sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) ";
$sql .= "and group_name in (".implode(", ", $parameter_names).") \n";
$sql .= "and permission_assigned = 'true' ";
$parameters['domain_uuid'] = $this->domain_uuid;
$group_permissions = $this->database->select($sql, $parameters, 'all');
//format the permission array
foreach ($group_permissions as $row) {
$permissions[$row['permission_name']] = 1;
}
//save permissions to this object
$this->permissions = $permissions;
}
/**
* save the assigned permissions to a session
* Saves the current permissions to the session.
*
* @return void
*/
public function session() {
if (!empty($this->permissions)) {
@@ -191,24 +243,14 @@ class permissions {
}
}
/**
* Returns a new permission object
*/
public static function new($database = null, $domain_uuid = null, $user_uuid = null) {
if (self::$permission === null) {
self::$permission = new permissions($database, $domain_uuid, $user_uuid);
}
return self::$permission;
}
}
//examples
/*
//add the permission
$p = permissions::new();
$p->add($permission);
//delete the permission
$p = permissions::new();
$p->delete($permission);
*/
/*
//add the permission
$p = permissions::new();
$p->add($permission);
//delete the permission
$p = permissions::new();
$p->delete($permission);
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,8 +3,8 @@
/**
* The settings class is used to load settings using hierarchical overriding
*
* The settings are loaded from the database tables default_settings, domain_settings, and user_settings in that order with
* Each setting overrides the setting from the previous table.
* The settings are loaded from the database tables default_settings, domain_settings, and user_settings in that order
* with Each setting overrides the setting from the previous table.
*
* @access public
* @author Mark Crane <mark@fusionpbx.com>
@@ -12,49 +12,59 @@
class settings implements clear_cache {
/**
* Set in the constructor. String used to load a specific domain. Must be a value domain UUID before sending to the constructor.
* Set in the constructor. String used to load a specific domain. Must be a value domain UUID before sending to the
* constructor.
*
* @var string
*/
private $domain_uuid;
/**
* Set in the constructor. String used to load a specific user. Must be a valid user UUID before sending to the constructor.
* Set in the constructor. String used to load a specific user. Must be a valid user UUID before sending to the
* constructor.
*
* @var string
*/
private $user_uuid;
/**
* Set in the constructor. String used for loading a specific device UUID
*
* @var string
*/
private $device_uuid;
/**
* Set in the constructor. String used for loading device profile
*
* @var string
*/
private $device_profile_uuid;
/**
* Set in the constructor. Current category set to load
*
* @var string
*/
private $category;
/**
* Internal array structure that is populated from the database
*
* @var array Array of settings loaded from Default Settings
*/
private $settings;
/**
* Set in the constructor. Must be a database object and cannot be null.
*
* @var database Database Object
*/
private $database;
/**
* Tracks if the APCu extension is loaded for database queries
*
* @var bool
*/
private $apcu_enabled;
@@ -63,9 +73,11 @@ class settings implements clear_cache {
* Create a settings object using key/value pairs in the $setting_array.
*
* Valid values are: database, domain_uuid, user_uuid, device_uuid, device_profile_uuid, and category.
*
* @param array setting_array
*
* @depends database::new()
* @access public
* @access public
*/
public function __construct($setting_array = []) {
@@ -89,7 +101,7 @@ class settings implements clear_cache {
//trap passing a PDO object instead of the required database object
if (!($this->database instanceof database)) {
//should never happen but will trap it here just-in-case
throw new \InvalidArgumentException("Database object passed in settings class constructor is not a valid database object");
throw new InvalidArgumentException("Database object passed in settings class constructor is not a valid database object");
}
//set the values from the array
@@ -102,14 +114,6 @@ class settings implements clear_cache {
$this->reload();
}
/**
* Returns the database object used in the settings
* @return database Object
*/
public function database(): database {
return $this->database;
}
/**
* Reloads the settings from the database
*/
@@ -144,107 +148,9 @@ class settings implements clear_cache {
}
}
/**
* Get the value utilizing the hierarchical overriding technique
* @param string|null $category Returns all settings when empty or the default value if the settings array is null
* @param string|null $subcategory Returns the array of category items when empty or the default value if the category array is null
* @param mixed $default_value allows default value returned if category and subcategory not found
*/
public function get(?string $category = null, ?string $subcategory = null, $default_value = null) {
//incremental refinement from all settings to a single setting
if (empty($category)) {
return $this->settings ?? $default_value;
}
elseif (empty($subcategory)) {
return $this->settings[$category] ?? $default_value;
}
else {
return $this->settings[$category][$subcategory] ?? $default_value;
}
}
/**
* Returns the domain_uuid in this object used to load the settings
* @return string UUID of the domain used to load the object or an empty string
*/
public function get_domain_uuid(): string {
if (!empty($this->domain_uuid)) {
return $this->domain_uuid;
}
return "";
}
/**
* Returns the user_uuid in this object used to load the settings
* @return string UUID of the user used to load the object or an empty string
*/
public function get_user_uuid(): string {
if (!empty($this->user_uuid)) {
return $this->user_uuid;
}
return "";
}
/**
* set the default, domain, user, device or device profile settings
* @param string $table_prefix prefix for the table.
* @param string $uuid uuid of the setting if available. If set to an empty string then a new uuid will be created.
* @param string $category Category of the setting.
* @param string $subcategory Subcategory of the setting.
* @param string $value (optional) Value to set. Default is empty string.
* @param string $type Type of the setting (array, numeric, text, etc)
* @param bool $enabled (optional) True or False. Default is True.
* @param string $description (optional) Description. Default is empty string.
*/
public function set(string $table_prefix, string $uuid, string $category, string $subcategory, string $value = "", string $type = 'text', bool $enabled = true, string $description = "") {
//set the table name
$table_name = $table_prefix.'_settings';
//init record as an array
$record = [];
if(!empty($this->domain_uuid)) {
$record[$table_name][0]['domain_uuid'] = $this->domain_uuid;
}
if(!empty($this->user_uuid)) {
$record[$table_name][0]['user_uuid'] = $this->user_uuid;
}
if(!empty($this->device_uuid)) {
$record[$table_name][0]['device_uuid'] = $this->device_uuid;
}
if(!empty($this->device_profile_uuid)) {
$record[$table_name][0]['device_profile_uuid'] = $this->device_profile_uuid;
}
if(!is_uuid($uuid)) {
$uuid = uuid();
}
//build the array
$record[$table_name][0][$table_prefix.'_setting_uuid' ] = $uuid;
$record[$table_name][0][$table_prefix.'_setting_category' ] = $category;
$record[$table_name][0][$table_prefix.'_setting_subcategory'] = $subcategory;
$record[$table_name][0][$table_prefix.'_setting_name' ] = $type;
$record[$table_name][0][$table_prefix.'_setting_value' ] = $value;
$record[$table_name][0][$table_prefix.'_setting_enabled' ] = $enabled;
$record[$table_name][0][$table_prefix.'_setting_description'] = $description;
//grant temporary permissions
$p = permissions::new();
$p->add($table_prefix.'_setting_add', 'temp');
$p->add($table_prefix.'_setting_edit', 'temp');
//execute insert
$this->database->app_name = $table_name;
$this->database->save($record);
//revoke temporary permissions
$p->delete($table_prefix.'_setting_add', 'temp');
$p->delete($table_prefix.'_setting_edit', 'temp');
}
/**
* Update the internal settings array with the default settings from the database
*
* @access private
*/
private function default_settings() {
@@ -275,14 +181,12 @@ class settings implements clear_cache {
if (isset($row['default_setting_value']) && $row['default_setting_value'] !== '') {
if ($name == "boolean") {
$this->settings[$category][$subcategory] = filter_var($row['default_setting_value'], FILTER_VALIDATE_BOOLEAN);
}
elseif ($name == "array") {
} elseif ($name == "array") {
if (!isset($this->settings[$category][$subcategory]) || !is_array($this->settings[$category][$subcategory])) {
$this->settings[$category][$subcategory] = array();
$this->settings[$category][$subcategory] = [];
}
$this->settings[$category][$subcategory][] = $row['default_setting_value'];
}
else {
} else {
$this->settings[$category][$subcategory] = $row['default_setting_value'];
}
}
@@ -297,6 +201,7 @@ class settings implements clear_cache {
/**
* Update the internal settings array with the domain settings from the database
*
* @access private
*/
private function domain_settings($domain_uuid = '', $i = 0) {
@@ -312,7 +217,7 @@ class settings implements clear_cache {
$this->domain_settings($uuid, $i++);
}
$key = 'settings_domain_'.$domain_uuid;
$key = 'settings_domain_' . $domain_uuid;
$result = '';
//if the apcu extension is loaded get the cached database result
@@ -336,7 +241,7 @@ class settings implements clear_cache {
$category = $row['domain_setting_category'];
$subcategory = $row['domain_setting_subcategory'];
if ($name == "array") {
$this->settings[$category][$subcategory] = array();
$this->settings[$category][$subcategory] = [];
}
}
@@ -351,11 +256,10 @@ class settings implements clear_cache {
}
if ($name == "array") {
if (!isset($this->settings[$category][$subcategory]) || !is_array($this->settings[$category][$subcategory])) {
$this->settings[$category][$subcategory] = array();
$this->settings[$category][$subcategory] = [];
}
$this->settings[$category][$subcategory][] = $row['domain_setting_value'];
}
else {
} else {
$this->settings[$category][$subcategory] = $row['domain_setting_value'];
}
}
@@ -366,11 +270,12 @@ class settings implements clear_cache {
/**
* Update the internal settings array with the user settings from the database
* @access private
*
* @access private
* @depends $this->domain_uuid
*/
private function user_settings() {
$key = 'settings_user_'.$this->user_uuid;
$key = 'settings_user_' . $this->user_uuid;
$result = '';
//if the apcu extension is loaded get the cached database result
if ($this->apcu_enabled && apcu_exists($key)) {
@@ -397,11 +302,9 @@ class settings implements clear_cache {
if (isset($row['user_setting_value']) && $row['user_setting_value'] !== '') {
if ($name == "boolean") {
$this->settings[$category][$subcategory] = filter_var($row['user_setting_value'], FILTER_VALIDATE_BOOLEAN);
}
elseif ($name == "array") {
} elseif ($name == "array") {
$this->settings[$category][$subcategory][] = $row['user_setting_value'];
}
else {
} else {
$this->settings[$category][$subcategory] = $row['user_setting_value'];
}
@@ -413,7 +316,8 @@ class settings implements clear_cache {
/**
* Update the internal settings array with the device profile settings from the database
* @access private
*
* @access private
* @depends $this->domain_uuid
*/
private function device_profile_settings() {
@@ -438,7 +342,8 @@ class settings implements clear_cache {
/**
* Update the internal settings array with the device settings from the database
* @access private
*
* @access private
* @depends $this->domain_uuid
*/
private function device_settings() {
@@ -461,6 +366,15 @@ class settings implements clear_cache {
}
}
/**
* Clears the APC cache and reloads the settings object.
*
* This method checks if APC is enabled on the server and if so, it clears
* any cached entries that start with "settings_". It then recreates the
* settings object to load all settings from the database.
*
* @return void
*/
public static function clear_cache() {
if (function_exists('apcu_enabled') && apcu_enabled()) {
$cache = apcu_cache_info(false);
@@ -484,4 +398,126 @@ class settings implements clear_cache {
}
}
}
/**
* Returns the database object used in the settings
*
* @return database Object
*/
public function database(): database {
return $this->database;
}
/**
* Returns the domain_uuid in this object used to load the settings
*
* @return string UUID of the domain used to load the object or an empty string
*/
public function get_domain_uuid(): string {
if (!empty($this->domain_uuid)) {
return $this->domain_uuid;
}
return "";
}
/**
* Returns the user_uuid in this object used to load the settings
*
* @return string UUID of the user used to load the object or an empty string
*/
public function get_user_uuid(): string {
if (!empty($this->user_uuid)) {
return $this->user_uuid;
}
return "";
}
/**
* Get the value utilizing the hierarchical overriding technique
*
* @param string|null $category Returns all settings when empty or the default value if the settings array is
* null
* @param string|null $subcategory Returns the array of category items when empty or the default value if the
* category array is null
* @param mixed $default_value allows default value returned if category and subcategory not found
*/
public function get(?string $category = null, ?string $subcategory = null, $default_value = null) {
//incremental refinement from all settings to a single setting
if (empty($category)) {
return $this->settings ?? $default_value;
} elseif (empty($subcategory)) {
return $this->settings[$category] ?? $default_value;
} else {
return $this->settings[$category][$subcategory] ?? $default_value;
}
}
/**
* Create or update an in-memory setting for a domain, user, device,
* or device profile.
*
* This method assembles a settings record, generates a UUID when needed,
* assigns ownership context (domain, user, device, or device profile),
* grants temporary permissions, and commits the record using the database
* abstraction layer. Only in-memory values are modified; this does not
* reload or apply settings system-wide.
*
* @param string $table_prefix Prefix used to build the settings table name.
* @param string $uuid UUID of the setting. A new UUID is generated
* if the provided value is empty or invalid.
* @param string $category Setting category.
* @param string $subcategory Setting subcategory.
* @param string $value Optional value for the setting. Defaults to an empty string.
* @param string $type Setting type (e.g. text, numeric, array).
* @param bool $enabled Whether the setting is enabled. Defaults to true.
* @param string $description Optional description for the setting.
*
* @return void
*/
public function set(string $table_prefix, string $uuid, string $category, string $subcategory, string $value = "", string $type = 'text', bool $enabled = true, string $description = "") {
//set the table name
$table_name = $table_prefix . '_settings';
//init record as an array
$record = [];
if (!empty($this->domain_uuid)) {
$record[$table_name][0]['domain_uuid'] = $this->domain_uuid;
}
if (!empty($this->user_uuid)) {
$record[$table_name][0]['user_uuid'] = $this->user_uuid;
}
if (!empty($this->device_uuid)) {
$record[$table_name][0]['device_uuid'] = $this->device_uuid;
}
if (!empty($this->device_profile_uuid)) {
$record[$table_name][0]['device_profile_uuid'] = $this->device_profile_uuid;
}
if (!is_uuid($uuid)) {
$uuid = uuid();
}
//build the array
$record[$table_name][0][$table_prefix . '_setting_uuid'] = $uuid;
$record[$table_name][0][$table_prefix . '_setting_category'] = $category;
$record[$table_name][0][$table_prefix . '_setting_subcategory'] = $subcategory;
$record[$table_name][0][$table_prefix . '_setting_name'] = $type;
$record[$table_name][0][$table_prefix . '_setting_value'] = $value;
$record[$table_name][0][$table_prefix . '_setting_enabled'] = $enabled;
$record[$table_name][0][$table_prefix . '_setting_description'] = $description;
//grant temporary permissions
$p = permissions::new();
$p->add($table_prefix . '_setting_add', 'temp');
$p->add($table_prefix . '_setting_edit', 'temp');
//execute insert
$this->database->app_name = $table_name;
$this->database->save($record);
//revoke temporary permissions
$p->delete($table_prefix . '_setting_add', 'temp');
$p->delete($table_prefix . '_setting_edit', 'temp');
}
}

View File

@@ -2,31 +2,36 @@
/**
* sounds class
*
* @method string get
*/
class sounds {
/**
* 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
*/
public $domain_uuid;
/**
* Additional public variables
*/
* Additional public variables
*/
public $sound_types;
public $full_path;
/**
* Set in the constructor. Must be a database object and cannot be null.
*
* @var database Database Object
*/
private $database;
/**
* 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(array $setting_array = []) {
//set domain and user UUIDs
@@ -37,76 +42,75 @@ class sounds {
}
/**
* Add a specific item in the cache
* @var array $array
* @var string $value string to be cached
* Retrieves a list of sound files based on the specified types.
*
* @return array A multidimensional array containing the sound files, where each sub-array has two keys: 'name' and
* 'value'.
*/
public function get() {
//miscellaneous
if (empty($this->sound_types) || (is_array($this->sound_types) && in_array('miscellaneous', $this->sound_types))) {
$x = 0;
if (if_group("superadmin")) {
$array['miscellaneous'][$x]['name'] = "say";
$array['miscellaneous'][$x]['value'] = "say:";
$x++;
$array['miscellaneous'][$x]['name'] = "tone_stream";
$array['miscellaneous'][$x]['value'] = "tone_stream:";
}
if (empty($this->sound_types) || (is_array($this->sound_types) && in_array('miscellaneous', $this->sound_types))) {
$x = 0;
if (if_group("superadmin")) {
$array['miscellaneous'][$x]['name'] = "say";
$array['miscellaneous'][$x]['value'] = "say:";
$x++;
$array['miscellaneous'][$x]['name'] = "tone_stream";
$array['miscellaneous'][$x]['value'] = "tone_stream:";
}
}
//recordings
if ((empty($this->sound_types) || (is_array($this->sound_types) && in_array('recordings', $this->sound_types))) && file_exists($_SERVER["PROJECT_ROOT"]."/app/recordings/app_config.php")) {
$sql = "select recording_name, recording_filename from v_recordings ";
$sql .= "where domain_uuid = :domain_uuid ";
$sql .= "order by recording_name asc ";
$parameters['domain_uuid'] = $_SESSION["domain_uuid"];
$recordings = $this->database->select($sql, $parameters, 'all');
if (is_array($recordings) && @sizeof($recordings) != 0) {
foreach ($recordings as $x => $row) {
$recording_name = $row["recording_name"];
$recording_filename = $row["recording_filename"];
$recording_path = !empty($this->full_path) && is_array($this->full_path) && in_array('recordings', $this->full_path) ? $_SESSION['switch']['recordings']['dir'].'/'.$_SESSION['domain_name'].'/' : null;
$array['recordings'][$x]['name'] = $recording_name;
$array['recordings'][$x]['value'] = $recording_path.$recording_filename;
}
if ((empty($this->sound_types) || (is_array($this->sound_types) && in_array('recordings', $this->sound_types))) && file_exists($_SERVER["PROJECT_ROOT"] . "/app/recordings/app_config.php")) {
$sql = "select recording_name, recording_filename from v_recordings ";
$sql .= "where domain_uuid = :domain_uuid ";
$sql .= "order by recording_name asc ";
$parameters['domain_uuid'] = $_SESSION["domain_uuid"];
$recordings = $this->database->select($sql, $parameters, 'all');
if (is_array($recordings) && @sizeof($recordings) != 0) {
foreach ($recordings as $x => $row) {
$recording_name = $row["recording_name"];
$recording_filename = $row["recording_filename"];
$recording_path = !empty($this->full_path) && is_array($this->full_path) && in_array('recordings', $this->full_path) ? $_SESSION['switch']['recordings']['dir'] . '/' . $_SESSION['domain_name'] . '/' : null;
$array['recordings'][$x]['name'] = $recording_name;
$array['recordings'][$x]['value'] = $recording_path . $recording_filename;
}
unset($sql, $parameters, $recordings, $row);
}
unset($sql, $parameters, $recordings, $row);
}
//phrases
if ((empty($this->sound_types) || (is_array($this->sound_types) && in_array('phrases', $this->sound_types))) && file_exists($_SERVER["PROJECT_ROOT"]."/app/phrases/app_config.php")) {
$sql = "select * from v_phrases ";
$sql .= "where domain_uuid = :domain_uuid ";
$parameters['domain_uuid'] = $_SESSION["domain_uuid"];
$phrases = $this->database->select($sql, $parameters, 'all');
if (is_array($phrases) && @sizeof($phrases) != 0) {
foreach ($phrases as $row) {
$array['phrases'][$x]['name'] = "phrase:".$row["phrase_name"];
$array['phrases'][$x]['value'] = "phrase:".$row["phrase_uuid"];
$x++;
}
if ((empty($this->sound_types) || (is_array($this->sound_types) && in_array('phrases', $this->sound_types))) && file_exists($_SERVER["PROJECT_ROOT"] . "/app/phrases/app_config.php")) {
$sql = "select * from v_phrases ";
$sql .= "where domain_uuid = :domain_uuid ";
$parameters['domain_uuid'] = $_SESSION["domain_uuid"];
$phrases = $this->database->select($sql, $parameters, 'all');
if (is_array($phrases) && @sizeof($phrases) != 0) {
foreach ($phrases as $row) {
$array['phrases'][$x]['name'] = "phrase:" . $row["phrase_name"];
$array['phrases'][$x]['value'] = "phrase:" . $row["phrase_uuid"];
$x++;
}
unset($sql, $parameters, $phrases, $row);
}
unset($sql, $parameters, $phrases, $row);
}
//sounds
if ((empty($this->sound_types) || (is_array($this->sound_types) && in_array('sounds', $this->sound_types))) && file_exists($_SERVER["PROJECT_ROOT"]."/app/phrases/app_config.php")) {
$file = new file;
$sound_files = $file->sounds();
if (is_array($sound_files) && @sizeof($sound_files) != 0) {
foreach ($sound_files as $value) {
if (substr($value, 0, 71) == "\$\${sounds_dir}/\${default_language}/\${default_dialect}/\${default_voice}/") {
$value = substr($value, 71);
}
$array['sounds'][$x]['name'] = $value;
$array['sounds'][$x]['value'] = $value;
$x++;
if ((empty($this->sound_types) || (is_array($this->sound_types) && in_array('sounds', $this->sound_types))) && file_exists($_SERVER["PROJECT_ROOT"] . "/app/phrases/app_config.php")) {
$file = new file;
$sound_files = $file->sounds();
if (is_array($sound_files) && @sizeof($sound_files) != 0) {
foreach ($sound_files as $value) {
if (substr($value, 0, 71) == "\$\${sounds_dir}/\${default_language}/\${default_dialect}/\${default_voice}/") {
$value = substr($value, 71);
}
$array['sounds'][$x]['name'] = $value;
$array['sounds'][$x]['value'] = $value;
$x++;
}
}
}
//send the results
return $array;
return $array;
}
}
?>

View File

@@ -5,291 +5,310 @@
*
* @method settings will add missing switch directories to default settings
*/
class switch_settings {
class switch_settings {
public $event_socket_ip_address;
public $event_socket_port;
public $event_socket_password;
public $event_socket_ip_address;
public $event_socket_port;
public $event_socket_password;
/**
* 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(array $setting_array = []) {
//set domain and user UUIDs
$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'] ?? '';
/**
* Constructor for the class.
*
* This method initializes the object with setting_array and session data.
*
* @param array $setting_array An optional array of settings to override default values. Defaults to [].
*/
public function __construct(array $setting_array = []) {
//set domain and user UUIDs
$this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
$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'] ?? '';
//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]);
}
/**
* settings Set switch directories in default settings
*/
public function settings() {
//connect to event socket
$esl = event_socket::create($this->event_socket_ip_address, $this->event_socket_port, $this->event_socket_password);
//run the api command
$result = $esl->request('api global_getvar');
//set the result as a named array
$vars = array();
foreach (explode("\n", $result) as $row) {
$a = explode("=", $row);
if (substr($a[0], -4) == "_dir") {
$vars[$a[0]] = $a[1];
}
}
//set defaults
$vars['base_dir'] = $vars['base_dir'] ?? '';
$vars['conf_dir'] = $vars['conf_dir'] ?? '';
$vars['db_dir'] = $vars['db_dir'] ?? '';
$vars['recordings_dir'] = $vars['recordings_dir'] ?? '';
$vars['script_dir'] = $vars['script_dir'] ?? '';
$vars['sounds_dir'] = $vars['sounds_dir'] ?? '';
$vars['storage_dir'] = $vars['storage_dir'] ?? '';
$vars['grammar_dir'] = $vars['grammar_dir'] ?? '';
$vars['log_dir'] = $vars['log_dir'] ?? '';
$vars['mod_dir'] = $vars['mod_dir'] ?? '';
//set the bin directory
if ($vars['base_dir'] == "/usr/local/freeswitch") {
$bin = '/usr/local/freeswitch/bin';
}
else {
$bin = '';
}
//create the default settings array
$x=0;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'bin';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $bin;
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'base';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['base_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'call_center';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'].'/autoload_configs';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'conf';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'db';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['db_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'dialplan';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'].'/dialplan';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'extensions';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'].'/directory';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'grammar';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['grammar_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'log';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['log_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'mod';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['mod_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'languages';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'].'/languages';
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'recordings';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['recordings_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'scripts';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['script_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'sip_profiles';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'].'/sip_profiles';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'sounds';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['sounds_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'storage';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['storage_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'voicemail';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['storage_dir'].'/voicemail';
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
//get an array of the default settings
$sql = "select * from v_default_settings ";
$sql .= "where default_setting_category = 'switch' ";
$default_settings = $this->database->select($sql, null, 'all');
unset($sql);
//find the missing default settings
$x = 0;
foreach ($array as $setting) {
$found = false;
$missing[$x] = $setting;
foreach ($default_settings as $row) {
if (trim($row['default_setting_subcategory']) == trim($setting['default_setting_subcategory'])) {
$found = true;
//remove items from the array that were found
unset($missing[$x]);
}
}
$x++;
}
unset($array);
//add the missing default settings
if (count($missing) > 0) {
$i = 1;
foreach ($missing as $row) {
//build insert array
$array['default_settings'][$i]['default_setting_uuid'] = uuid();
$array['default_settings'][$i]['default_setting_category'] = $row['default_setting_category'];
$array['default_settings'][$i]['default_setting_subcategory'] = $row['default_setting_subcategory'];
$array['default_settings'][$i]['default_setting_name'] = $row['default_setting_name'];
$array['default_settings'][$i]['default_setting_value'] = $row['default_setting_value'];
$array['default_settings'][$i]['default_setting_enabled'] = $row['default_setting_enabled'];
$array['default_settings'][$i]['default_setting_description'] = $row['default_setting_description'];
//increment the row id
$i++;
}
if (is_array($array) && @sizeof($array) != 0) {
//grant temporary permissions
$p = permissions::new();
$p->add('default_setting_add', 'temp');
//execute insert
$this->database->save($array);
//clear the apcu cache
settings::clear_cache();
//revoke temporary permissions
$p->delete('default_setting_add', 'temp');
}
unset($missing);
}
//set the default settings
if (!empty($array) && is_array($array)) {
foreach ($array as $row) {
if (isset($row['default_setting_enabled']) && $row['default_setting_enabled'] == "true" && isset($row['default_setting_subcategory'])) {
$_SESSION['switch'][$row['default_setting_subcategory']][$row['default_setting_name']] = $row['default_setting_value'] ?? '';
}
}
}
//unset the array variable
unset($array);
}
}
/**
* Get the default settings for the application.
*
* This method retrieves the default settings from the event socket and
* creates an array of default setting categories, subcategories, names,
* values, and descriptions.
*
* @return array An array of default settings.
*/
public function settings() {
//connect to event socket
$esl = event_socket::create($this->event_socket_ip_address, $this->event_socket_port, $this->event_socket_password);
//run the api command
$result = $esl->request('api global_getvar');
//set the result as a named array
$vars = [];
foreach (explode("\n", $result) as $row) {
$a = explode("=", $row);
if (substr($a[0], -4) == "_dir") {
$vars[$a[0]] = $a[1];
}
}
//set defaults
$vars['base_dir'] = $vars['base_dir'] ?? '';
$vars['conf_dir'] = $vars['conf_dir'] ?? '';
$vars['db_dir'] = $vars['db_dir'] ?? '';
$vars['recordings_dir'] = $vars['recordings_dir'] ?? '';
$vars['script_dir'] = $vars['script_dir'] ?? '';
$vars['sounds_dir'] = $vars['sounds_dir'] ?? '';
$vars['storage_dir'] = $vars['storage_dir'] ?? '';
$vars['grammar_dir'] = $vars['grammar_dir'] ?? '';
$vars['log_dir'] = $vars['log_dir'] ?? '';
$vars['mod_dir'] = $vars['mod_dir'] ?? '';
//set the bin directory
if ($vars['base_dir'] == "/usr/local/freeswitch") {
$bin = '/usr/local/freeswitch/bin';
} else {
$bin = '';
}
//create the default settings array
$x = 0;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'bin';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $bin;
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'base';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['base_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'call_center';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'] . '/autoload_configs';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'conf';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'db';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['db_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'dialplan';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'] . '/dialplan';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'extensions';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'] . '/directory';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'grammar';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['grammar_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'log';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['log_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'mod';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['mod_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'languages';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'] . '/languages';
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'recordings';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['recordings_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'scripts';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['script_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'sip_profiles';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['conf_dir'] . '/sip_profiles';
$array[$x]['default_setting_enabled'] = 'false';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'sounds';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['sounds_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'storage';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['storage_dir'];
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
$array[$x]['default_setting_category'] = 'switch';
$array[$x]['default_setting_subcategory'] = 'voicemail';
$array[$x]['default_setting_name'] = 'dir';
$array[$x]['default_setting_value'] = $vars['storage_dir'] . '/voicemail';
$array[$x]['default_setting_enabled'] = 'true';
$array[$x]['default_setting_description'] = '';
$x++;
//get an array of the default settings
$sql = "select * from v_default_settings ";
$sql .= "where default_setting_category = 'switch' ";
$default_settings = $this->database->select($sql, null, 'all');
unset($sql);
//find the missing default settings
$x = 0;
foreach ($array as $setting) {
$found = false;
$missing[$x] = $setting;
foreach ($default_settings as $row) {
if (trim($row['default_setting_subcategory']) == trim($setting['default_setting_subcategory'])) {
$found = true;
//remove items from the array that were found
unset($missing[$x]);
}
}
$x++;
}
unset($array);
//add the missing default settings
if (count($missing) > 0) {
$i = 1;
foreach ($missing as $row) {
//build insert array
$array['default_settings'][$i]['default_setting_uuid'] = uuid();
$array['default_settings'][$i]['default_setting_category'] = $row['default_setting_category'];
$array['default_settings'][$i]['default_setting_subcategory'] = $row['default_setting_subcategory'];
$array['default_settings'][$i]['default_setting_name'] = $row['default_setting_name'];
$array['default_settings'][$i]['default_setting_value'] = $row['default_setting_value'];
$array['default_settings'][$i]['default_setting_enabled'] = $row['default_setting_enabled'];
$array['default_settings'][$i]['default_setting_description'] = $row['default_setting_description'];
//increment the row id
$i++;
}
if (is_array($array) && @sizeof($array) != 0) {
//grant temporary permissions
$p = permissions::new();
$p->add('default_setting_add', 'temp');
//execute insert
$this->database->save($array);
//clear the apcu cache
settings::clear_cache();
//revoke temporary permissions
$p->delete('default_setting_add', 'temp');
}
unset($missing);
}
//set the default settings
if (!empty($array) && is_array($array)) {
foreach ($array as $row) {
if (isset($row['default_setting_enabled']) && $row['default_setting_enabled'] == "true" && isset($row['default_setting_subcategory'])) {
$_SESSION['switch'][$row['default_setting_subcategory']][$row['default_setting_name']] = $row['default_setting_value'] ?? '';
}
}
}
//unset the array variable
unset($array);
}
}

View File

@@ -25,67 +25,91 @@
*/
//define the template class
class template {
class template {
public $engine;
public $template_dir;
public $cache_dir;
private $object;
private $var_array;
public $engine;
public $template_dir;
public $cache_dir;
private $object;
private $var_array;
public function __construct(){
}
public function __construct() {
}
public function init() {
if ($this->engine === 'smarty') {
require_once "resources/templates/engine/smarty/Smarty.class.php";
$this->object = new Smarty();
$this->object->setTemplateDir($this->template_dir);
$this->object->setCompileDir($this->cache_dir);
$this->object->setCacheDir($this->cache_dir);
$this->object->registerPlugin("modifier","in_array", "in_array");
}
if ($this->engine === 'raintpl') {
require_once "resources/templates/engine/raintpl/rain.tpl.class.php";
$this->object = new RainTPL();
RainTPL::configure('tpl_dir', realpath($this->template_dir)."/");
RainTPL::configure('cache_dir', realpath($this->cache_dir)."/");
}
if ($this->engine === 'twig') {
require_once "resources/templates/engine/Twig/Autoloader.php";
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem($this->template_dir);
$this->object = new Twig_Environment($loader);
$lexer = new Twig_Lexer($this->object, array(
'tag_comment' => array('{*', '*}'),
'tag_block' => array('{', '}'),
'tag_variable' => array('{$', '}'),
));
$this->object->setLexer($lexer);
}
}
public function assign($key, $value) {
if ($this->engine === 'smarty') {
$this->object->assign($key, $value);
}
if ($this->engine === 'raintpl') {
$this->object->assign($key, $value);
}
if ($this->engine === 'twig') {
$this->var_array[$key] = $value;
}
}
public function render($name) {
if ($this->engine === 'smarty') {
return $this->object->fetch($name);
}
if ($this->engine === 'raintpl') {
return $this->object-> draw($name, 'return_string=true');
}
if ($this->engine === 'twig') {
return $this->object->render($name,$this->var_array);
}
}
/**
* Initializes the template engine based on the selected engine.
*
* @access public
*/
public function init() {
if ($this->engine === 'smarty') {
require_once "resources/templates/engine/smarty/Smarty.class.php";
$this->object = new Smarty();
$this->object->setTemplateDir($this->template_dir);
$this->object->setCompileDir($this->cache_dir);
$this->object->setCacheDir($this->cache_dir);
$this->object->registerPlugin("modifier", "in_array", "in_array");
}
if ($this->engine === 'raintpl') {
require_once "resources/templates/engine/raintpl/rain.tpl.class.php";
$this->object = new RainTPL();
RainTPL::configure('tpl_dir', realpath($this->template_dir) . "/");
RainTPL::configure('cache_dir', realpath($this->cache_dir) . "/");
}
if ($this->engine === 'twig') {
require_once "resources/templates/engine/Twig/Autoloader.php";
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem($this->template_dir);
$this->object = new Twig_Environment($loader);
$lexer = new Twig_Lexer($this->object, [
'tag_comment' => ['{*', '*}'],
'tag_block' => ['{', '}'],
'tag_variable' => ['{$', '}'],
]);
$this->object->setLexer($lexer);
}
}
/**
* Assigns a value to the template engine based on the selected engine.
*
* @param string $key The key for the assigned value.
* @param mixed $value The value to be assigned.
*
* @access public
*
* @return void
*/
public function assign($key, $value) {
if ($this->engine === 'smarty') {
$this->object->assign($key, $value);
}
if ($this->engine === 'raintpl') {
$this->object->assign($key, $value);
}
if ($this->engine === 'twig') {
$this->var_array[$key] = $value;
}
}
/**
* Renders the given template using the configured engine.
*
* @param string $name Name of the template to render. Values can be 'smarty', 'raintpl' or 'twig' (case sensitive)
*
* @return mixed The rendered template output, depending on the used engine
*
* @access public
*/
public function render($name) {
if ($this->engine === 'smarty') {
return $this->object->fetch($name);
}
if ($this->engine === 'raintpl') {
return $this->object->draw($name, 'return_string=true');
}
if ($this->engine === 'twig') {
return $this->object->render($name, $this->var_array);
}
}
}

View File

@@ -6,17 +6,24 @@
*/
class text implements clear_cache {
/**
* Translated flattened text array using the file path as key
*
* @var array
*/
private static $tanslated;
/**
* Contains the list of supported languages
*
* @var array
*/
public $languages;
/**
* Legacy older list of supported languages
*
* @var array
*/
public $legacy_map = array(
public $legacy_map = [
'he' => 'he-il',
'pl' => 'pl-pl',
'uk' => 'uk-ua',
@@ -30,439 +37,94 @@ class text implements clear_cache {
'es' => 'es-cl',
'fr' => 'fr-fr',
'pt' => 'pt-pt',
);
];
/**
* 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;
/**
* Translated flattened text array using the file path as key
* @var array
*/
private static $tanslated;
/**
* @var bool
*/
private $apcu_enabled;
/**
* 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 = []) {
//define the text array
$text = array();
$text = [];
//check for apcu caching
$this->apcu_enabled = function_exists('apcu_enabled') && apcu_enabled();
$this->apcu_enabled = function_exists('apcu_enabled') && apcu_enabled();
//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'] ?? '';
$this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? '';
$this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? '';
//open a database connection
if (empty($setting_array['database'])) {
$this->database = database::new();
} else {
$this->database = $setting_array['database'];
}
if (empty($setting_array['database'])) {
$this->database = database::new();
} else {
$this->database = $setting_array['database'];
}
//load the settings
if (empty($setting_array['settings'])) {
$this->settings = new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
} else {
$this->settings = $setting_array['settings'];
}
if (empty($setting_array['settings'])) {
$this->settings = new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]);
} else {
$this->settings = $setting_array['settings'];
}
//get the global app_languages.php so we can get the list of languages
if (file_exists($_SERVER["PROJECT_ROOT"]."/resources/app_languages.php")) {
include $_SERVER["PROJECT_ROOT"]."/resources/app_languages.php";
}
if (file_exists($_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php")) {
include $_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php";
}
//get the list of languages, remove en-us, sort it then put en-us in front
unset($text['language-name']['en-us']);
if (is_array($text['language-name'])) {
$languages = array_keys($text['language-name']);
asort($languages);
array_unshift($languages, 'en-us');
}
//support legacy variable
if (is_array($languages)) {
$_SESSION['app']['languages'] = $languages;
$this->languages = $languages;
}
}
/**
* Get a specific language from the language file
* @param string|null $language_code examples: en-us, es-cl, fr-fr, pt-pt
* @param string|null $app_path examples: app/exec or core/domains
* @param bool $exclude_global Exclude the global languages file
*
* @return array A flattened array containing the desired language
*/
public function get(?string $language_code = null, ?string $app_path = null, bool $exclude_global = false) {
//define the text array
$text = [];
//check the session language
if ($language_code == null) {
$language_code = $this->settings->get('domain', 'language', 'en-us');
}
//check the language code
if (strlen($language_code) == 2 && array_key_exists($language_code, $this->legacy_map)) {
$language_code = $this->legacy_map[$language_code];
}
//get the app_languages.php
if ($app_path != null) {
$lang_path = $_SERVER["PROJECT_ROOT"]."/".$app_path;
}
else {
$lang_path = getcwd();
}
//check the class cache
$cache_key = "text_{$language_code}_{$lang_path}";
if ($this->apcu_enabled && apcu_exists($cache_key)) {
return apcu_fetch($cache_key);
}
if (isset(self::$tanslated[$cache_key])) {
return self::$tanslated[$cache_key];
}
//get the global app_languages.php
if (!$exclude_global && file_exists($_SERVER["PROJECT_ROOT"]."/resources/app_languages.php")) {
require $_SERVER["PROJECT_ROOT"]."/resources/app_languages.php";
}
if (file_exists($lang_path."/app_languages.php") && ($lang_path != 'resources' or $exclude_global)) {
include "{$lang_path}/app_languages.php";
}
//else {
// throw new Exception("could not find app_languages for '$app_path'");
//}
//reduce to specific language
if ($language_code != 'all' && is_array($text)) {
foreach ($text as $key => $value) {
if (isset($value[$language_code]) && !empty($value[$language_code])) {
//use the selected language
$text[$key] = $value[$language_code];
} elseif (isset($value['en-us'])) {
//fallback to en-us
$text[$key] = $value['en-us'];
} else {
$text[$key] = '';
}
}
}
//cache the reduced language using the file as a key
if ($this->apcu_enabled) {
apcu_store($cache_key, $text);
} else {
self::$tanslated[$cache_key] = $text;
}
//return the array of translations
return $text;
}
/**
* reorganize an app_languages.php into a consistent format
* @var string $app_path examples: app/exec or core/domains
* @var string $no_sort don't sort the text label order
*/
public function organize_language($app_path = null, $no_sort = false) {
//clear $text ready for the import
$text = array();
//get the app_languages.php
if ($app_path == null) {
throw new Exception("\$app_path must be specified");
}
$lang_path = $_SERVER["PROJECT_ROOT"]."/$app_path/app_languages.php";
if (!file_exists($lang_path)) {
throw new Exception("could not find app_languages for '$app_path'");
}
require $lang_path;
if (!is_array($text)) {
throw new Exception("failed to import text data from '$app_path'");
}
//collect existing comments
$comment = array();
$file_handle = fopen($lang_path, "r");
while (!feof($file_handle)) {
if(preg_match('/\$text\[[\'"](.+)[\'"]\]\[[\'"](.+)[\'"]]\s+=\s+[\'"].*[\'"];\s+\/\/(.+)/', fgets($file_handle), $matches)){
$comment[$matches[0]][$matches[1]] = $matches[2];
}
}
fclose($file_handle);
//open the language file for writing
$lang_file = fopen($lang_path, 'w');
date_default_timezone_set('UTC');
fwrite($lang_file, "<?php\n#This file was last reorganized on " . date("jS \of F Y h:i:s A e") . "\n");
if (!$no_sort) {
if ($app_path == 'resources') {
$temp_A['language-name'] = $text['language-name'];
unset($text['language-name']);
foreach($this->languages as $language) {
$temp_B["language-$language"] = $text["language-$language"];
unset($text["language-$language"]);
}
$temp_C["language-en-us"] = $temp_B["language-en-us"];
unset($temp_B["language-en-us"]);
ksort($temp_B);
$temp_B = array_merge($temp_C, $temp_B);
ksort($text);
$text = array_merge($temp_A, $temp_B, $text);
unset($temp_A, $temp_B, $temp_C);
}
else {
ksort($text);
}
}
else {
if ($app_path == 'resources') {
foreach($this->languages as $language) {
$label = array_shift($text["language-$language"]);
if (empty($label))
$label = $language;
$text["language-$language"]['en-us'] = $label;
}
}
}
$last_lang_label = "";
foreach ($text as $lang_label => $lang_codes) {
//behave differently if we are one of the special language-* tags
if (preg_match('/\Alanguage-(\w{2}|\w{2}-\w{2})\z/', $lang_label, $lang_code)) {
if ($lang_label == 'language-en-us')
fwrite($lang_file, "\n");
$target_lang = $lang_code[1];
if (strlen($target_lang) == 2) {
if (array_key_exists($target_lang, $this->legacy_map)) {
$target_lang = $this->legacy_map[$target_lang];
}
}
$spacer = "";
if (strlen($target_lang) == 11)
$spacer = " ";
$language_name = $this->escape_str(array_shift($text[$lang_label]));
if (empty($language_name))
$language_name = $this->escape_str($target_lang);
fwrite($lang_file, "\$text['language-$target_lang'$spacer]['en-us'] = \"$language_name\";\n");
}
else {
//put a line break in between the last tag if it has changed
if ($last_lang_label != $lang_label)
fwrite($lang_file, "\n");
foreach ($this->languages as $lang_code) {
$value = "";
$append = "";
$spacer = "";
$target_lang = $lang_code;
if (strlen($lang_code) == 2) {
if (array_key_exists($lang_code, $this->legacy_map)) {
$target_lang = $this->legacy_map[$lang_code];
}
}
if (strlen($target_lang) == 2)
$spacer = " ";
if (array_key_exists($lang_code, $text[$lang_label]))
$value = $text[$lang_label][$lang_code];
if (empty($value) and array_key_exists($target_lang, $this->legacy_map)) {
$value = $text[$lang_label][$this->legacy_map[$target_lang]];
}
$base_code = substr($target_lang, 0, 2);
if (!empty($value)
and array_key_exists($base_code, $this->legacy_map )
and $this->legacy_map[$base_code] != $target_lang
and $value == $text[$lang_label][$this->legacy_map[$base_code]]
) {
$append = " //copied from ".$this->legacy_map[$base_code];
}
if (empty($value)) {
foreach($this->languages as $lang_code) {
if (substr($lang_code, 0, 2) == $base_code and !empty($text[$lang_label][$lang_code])) {
$value = $text[$lang_label][$lang_code];
$append = " //copied from $lang_code";
continue;
}
}
}
if(empty($append) && array_key_exists($comment[$lang_label], $lang_code)) {
$append = " //$comment[$lang_label][$lang_code]";
}
fwrite($lang_file, "\$text['$lang_label']['$target_lang'$spacer] = \"".$this->escape_str($value)."\";$append\n");
}
}
$last_lang_label = $lang_label;
}
//close the language file
fwrite($lang_file, "\n?>\n");
fclose($lang_file);
}
/**
* Detect all languages from the application and session language settings.
*
* @param bool $no_sort Flag to prevent sorting of detected languages.
*
* @return void
*/
public function detect_all_languages($no_sort = false) {
//clear $text ready for the import
$text = array();
$languages = array();
//retrieve all the languages
$files = glob($_SERVER["PROJECT_ROOT"] . "/*/*/app_languages.php");
foreach($files as $file) {
include $file;
}
include $_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php";
//check every tag
foreach($text as $lang_codes) {
foreach($lang_codes as $language_code => $value) {
if (strlen($language_code) == 2) {
if (array_key_exists($language_code, $this->legacy_map)) {
$language_code = $this->legacy_map[$language_code];
}
}
$languages[$language_code] = 1;
}
}
//set $this->languages up according to what we found
unset($languages['en-us']);
$languages = array_keys($languages);
unset($text['language-name']['en-us']);
if (is_array($text['language-name'])) {
$languages = array_keys($text['language-name']);
asort($languages);
array_unshift($languages, 'en-us');
}
//support legacy variable
if (is_array($languages)) {
$_SESSION['app']['languages'] = $languages;
$this->languages = $languages;
//rewrite resources/app_languges
$this->organize_language('resources', $no_sort);
}
/**
* Get totals of language usage across all languages and applications.
*
* This method retrieves the total number of translations, menu items,
* and application descriptions for each language, as well as a total count
* for each category.
*
* @return array A nested array containing the total counts for languages, menu items, and app descriptions
*/
public function language_totals() {
//setup variables
$language_totals = array();
$language_totals['languages']['total'] = 0;
$language_totals['menu_items']['total'] = 0;
$language_totals['app_descriptions']['total'] = 0;
foreach ($this->languages as $language_code) {
$language_totals[$language_code] = 0;
}
//retrieve all the languages
$text = array();
$files = glob($_SERVER["PROJECT_ROOT"] . "/*/*/app_languages.php");
foreach($files as $file) {
include $file;
}
include $_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php";
//check every tag
foreach($text as $label_name => $values) {
$language_totals['languages']['total']++;
foreach ($this->languages as $language_code) {
if (!empty($values[$language_code]))
$language_totals['languages'][$language_code]++;
}
}
unset($text);
//retrieve all the menus
$x = 0;
$files = glob($_SERVER["PROJECT_ROOT"] . "/*/*");
foreach($files as $file) {
if (file_exists($file . "/app_menu.php"))
include $file . "/app_menu.php";
if (file_exists($file . "/app_config.php"))
include $file . "/app_config.php";
$x++;
}
//check every tag
foreach ($apps as $app) {
$language_totals['app_descriptions']['total']++;
foreach($app['menu'] as $menu_item) {
$language_totals['menu_items']['total']++;
foreach ($this->languages as $language_code) {
if (!empty($menu_item['title'][$language_code]))
$language_totals['menu_items'][$language_code]++;
}
}
foreach ($this->languages as $language_code) {
if (!empty($app['description'][$language_code])) {
$language_totals['app_descriptions'][$language_code]++;
}
}
}
return $language_totals;
}
private function escape_str($string = '') {
//perform initial escape
$string = addslashes(stripslashes($string));
//swap \' as we don't need to escape those
return preg_replace("/\\\'/", "'", $string);
//escape " as we write our strings double quoted
return preg_replace("/\"/", '\"', $string);
}
}
/**
* The clear_cache method is called automatically for any class that implements the clear_cache interface.
* The function declared here ensures that all clear_cache methods have the same number of parameters being passed, which in this case, is no parameters.
* The function declared here ensures that all clear_cache methods have the same number of parameters being passed,
* which in this case, are no parameters.
*/
public static function clear_cache() {
//check for apcu extension and if is enabled
@@ -485,4 +147,356 @@ class text implements clear_cache {
}
}
}
/**
* Get a specific language from the language file
*
* @param string|null $language_code examples: en-us, es-cl, fr-fr, pt-pt
* @param string|null $app_path examples: app/exec or core/domains
* @param bool $exclude_global Exclude the global languages file
*
* @return array A flattened array containing the desired language
*/
public function get(?string $language_code = null, ?string $app_path = null, bool $exclude_global = false) {
//define the text array
$text = [];
//check the session language
if ($language_code == null) {
$language_code = $this->settings->get('domain', 'language', 'en-us');
}
//check the language code
if (strlen($language_code) == 2 && array_key_exists($language_code, $this->legacy_map)) {
$language_code = $this->legacy_map[$language_code];
}
//get the app_languages.php
if ($app_path != null) {
$lang_path = $_SERVER["PROJECT_ROOT"] . "/" . $app_path;
} else {
$lang_path = getcwd();
}
//check the class cache
$cache_key = "text_{$language_code}_{$lang_path}";
if ($this->apcu_enabled && apcu_exists($cache_key)) {
return apcu_fetch($cache_key);
}
if (isset(self::$tanslated[$cache_key])) {
return self::$tanslated[$cache_key];
}
//get the global app_languages.php
if (!$exclude_global && file_exists($_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php")) {
require $_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php";
}
if (file_exists($lang_path . "/app_languages.php") && ($lang_path != 'resources' or $exclude_global)) {
include "{$lang_path}/app_languages.php";
}
//else {
// throw new Exception("could not find app_languages for '$app_path'");
//}
//reduce to specific language
if ($language_code != 'all' && is_array($text)) {
foreach ($text as $key => $value) {
if (isset($value[$language_code]) && !empty($value[$language_code])) {
//use the selected language
$text[$key] = $value[$language_code];
} elseif (isset($value['en-us'])) {
//fallback to en-us
$text[$key] = $value['en-us'];
} else {
$text[$key] = '';
}
}
}
//cache the reduced language using the file as a key
if ($this->apcu_enabled) {
apcu_store($cache_key, $text);
} else {
self::$tanslated[$cache_key] = $text;
}
//return the array of translations
return $text;
}
/**
* Detect all languages from the application and session language settings.
*
* @param bool $no_sort Flag to prevent sorting of detected languages.
*
* @return void
*/
public function detect_all_languages($no_sort = false) {
//clear $text ready for the import
$text = [];
$languages = [];
//retrieve all the languages
$files = glob($_SERVER["PROJECT_ROOT"] . "/*/*/app_languages.php");
foreach ($files as $file) {
include $file;
}
include $_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php";
//check every tag
foreach ($text as $lang_codes) {
foreach ($lang_codes as $language_code => $value) {
if (strlen($language_code) == 2) {
if (array_key_exists($language_code, $this->legacy_map)) {
$language_code = $this->legacy_map[$language_code];
}
}
$languages[$language_code] = 1;
}
}
//set $this->languages up according to what we found
unset($languages['en-us']);
$languages = array_keys($languages);
asort($languages);
array_unshift($languages, 'en-us');
//support legacy variable
$_SESSION['app']['languages'] = $languages;
$this->languages = $languages;
//rewrite resources/app_languges
$this->organize_language('resources', $no_sort);
}
/**
* Organize a specific language from the language file.
*
* @param string $app_path Path to the application where the language file is located.
* @param bool $no_sort Flag to determine if the text should be sorted or not.
*
* @return void
*/
public function organize_language($app_path = null, $no_sort = false) {
//clear $text ready for the import
$text = [];
//get the app_languages.php
if ($app_path == null) {
throw new Exception("\$app_path must be specified");
}
$lang_path = $_SERVER["PROJECT_ROOT"] . "/$app_path/app_languages.php";
if (!file_exists($lang_path)) {
throw new Exception("could not find app_languages for '$app_path'");
}
require $lang_path;
if (!is_array($text)) {
throw new Exception("failed to import text data from '$app_path'");
}
//collect existing comments
$comment = [];
$file_handle = fopen($lang_path, "r");
while (!feof($file_handle)) {
if (preg_match('/\$text\[[\'"](.+)[\'"]\]\[[\'"](.+)[\'"]]\s+=\s+[\'"].*[\'"];\s+\/\/(.+)/', fgets($file_handle), $matches)) {
$comment[$matches[0]][$matches[1]] = $matches[2];
}
}
fclose($file_handle);
//open the language file for writing
$lang_file = fopen($lang_path, 'w');
date_default_timezone_set('UTC');
fwrite($lang_file, "<?php\n#This file was last reorganized on " . date("jS \of F Y h:i:s A e") . "\n");
if (!$no_sort) {
if ($app_path == 'resources') {
$temp_A['language-name'] = $text['language-name'];
unset($text['language-name']);
foreach ($this->languages as $language) {
$temp_B["language-$language"] = $text["language-$language"];
unset($text["language-$language"]);
}
$temp_C["language-en-us"] = $temp_B["language-en-us"];
unset($temp_B["language-en-us"]);
ksort($temp_B);
$temp_B = array_merge($temp_C, $temp_B);
ksort($text);
$text = array_merge($temp_A, $temp_B, $text);
unset($temp_A, $temp_B, $temp_C);
} else {
ksort($text);
}
} else {
if ($app_path == 'resources') {
foreach ($this->languages as $language) {
$label = array_shift($text["language-$language"]);
if (empty($label))
$label = $language;
$text["language-$language"]['en-us'] = $label;
}
}
}
$last_lang_label = "";
foreach ($text as $lang_label => $lang_codes) {
//behave differently if we are one of the special language-* tags
if (preg_match('/\Alanguage-(\w{2}|\w{2}-\w{2})\z/', $lang_label, $lang_code)) {
if ($lang_label == 'language-en-us')
fwrite($lang_file, "\n");
$target_lang = $lang_code[1];
if (strlen($target_lang) == 2) {
if (array_key_exists($target_lang, $this->legacy_map)) {
$target_lang = $this->legacy_map[$target_lang];
}
}
$spacer = "";
if (strlen($target_lang) == 11)
$spacer = " ";
$language_name = $this->escape_str(array_shift($text[$lang_label]));
if (empty($language_name))
$language_name = $this->escape_str($target_lang);
fwrite($lang_file, "\$text['language-$target_lang'$spacer]['en-us'] = \"$language_name\";\n");
} else {
//put a line break in between the last tag if it has changed
if ($last_lang_label != $lang_label)
fwrite($lang_file, "\n");
foreach ($this->languages as $lang_code) {
$value = "";
$append = "";
$spacer = "";
$target_lang = $lang_code;
if (strlen($lang_code) == 2) {
if (array_key_exists($lang_code, $this->legacy_map)) {
$target_lang = $this->legacy_map[$lang_code];
}
}
if (strlen($target_lang) == 2)
$spacer = " ";
if (array_key_exists($lang_code, $text[$lang_label]))
$value = $text[$lang_label][$lang_code];
if (empty($value) and array_key_exists($target_lang, $this->legacy_map)) {
$value = $text[$lang_label][$this->legacy_map[$target_lang]];
}
$base_code = substr($target_lang, 0, 2);
if (!empty($value)
and array_key_exists($base_code, $this->legacy_map)
and $this->legacy_map[$base_code] != $target_lang
and $value == $text[$lang_label][$this->legacy_map[$base_code]]
) {
$append = " //copied from " . $this->legacy_map[$base_code];
}
if (empty($value)) {
foreach ($this->languages as $lang_code) {
if (substr($lang_code, 0, 2) == $base_code and !empty($text[$lang_label][$lang_code])) {
$value = $text[$lang_label][$lang_code];
$append = " //copied from $lang_code";
continue;
}
}
}
if (empty($append) && array_key_exists($comment[$lang_label], $lang_code)) {
$append = " //$comment[$lang_label][$lang_code]";
}
fwrite($lang_file, "\$text['$lang_label']['$target_lang'$spacer] = \"" . $this->escape_str($value) . "\";$append\n");
}
}
$last_lang_label = $lang_label;
}
//close the language file
fwrite($lang_file, "\n?>\n");
fclose($lang_file);
}
/**
* Escapes special characters in a string for use in a SQL query.
*
* @param string $string The input string to be escaped. Defaults to an empty string if not provided.
*
* @return string The escaped string.
*/
private function escape_str($string = '') {
//perform initial escape
$string = addslashes(stripslashes($string));
//swap \' as we don't need to escape those
return preg_replace("/\\\'/", "'", $string);
//escape " as we write our strings double quoted
return preg_replace("/\"/", '\"', $string);
}
/**
* Get totals of language usage across all languages and applications.
*
* This method retrieves the total number of translations, menu items,
* and application descriptions for each language, as well as a total count
* for each category.
*
* @return array A nested array containing the total counts for languages, menu items, and app descriptions
*/
public function language_totals() {
//setup variables
$language_totals = [];
$language_totals['languages']['total'] = 0;
$language_totals['menu_items']['total'] = 0;
$language_totals['app_descriptions']['total'] = 0;
foreach ($this->languages as $language_code) {
$language_totals[$language_code] = 0;
}
//retrieve all the languages
$text = [];
$files = glob($_SERVER["PROJECT_ROOT"] . "/*/*/app_languages.php");
foreach ($files as $file) {
include $file;
}
include $_SERVER["PROJECT_ROOT"] . "/resources/app_languages.php";
//check every tag
foreach ($text as $label_name => $values) {
$language_totals['languages']['total']++;
foreach ($this->languages as $language_code) {
if (!empty($values[$language_code]))
$language_totals['languages'][$language_code]++;
}
}
unset($text);
//retrieve all the menus
$x = 0;
$files = glob($_SERVER["PROJECT_ROOT"] . "/*/*");
foreach ($files as $file) {
if (file_exists($file . "/app_menu.php"))
include $file . "/app_menu.php";
if (file_exists($file . "/app_config.php"))
include $file . "/app_config.php";
$x++;
}
//check every tag
foreach ($apps as $app) {
$language_totals['app_descriptions']['total']++;
foreach ($app['menu'] as $menu_item) {
$language_totals['menu_items']['total']++;
foreach ($this->languages as $language_code) {
if (!empty($menu_item['title'][$language_code]))
$language_totals['menu_items'][$language_code]++;
}
}
foreach ($this->languages as $language_code) {
if (!empty($app['description'][$language_code])) {
$language_totals['app_descriptions'][$language_code]++;
}
}
}
return $language_totals;
}
}

View File

@@ -32,78 +32,42 @@
class token {
/**
* Called when the object is created
*/
* Called when the object is created
*/
//public $code;
/**
* Class constructor
*/
* Class constructor
*/
public function __construct() {
}
/**
* Create the token
*
* @var string $key
*/
public function create($key) {
//clear previously validated tokens
$this->clear_validated();
$this->clear_validated();
//allow only specific characters
$key = preg_replace('[^a-zA-Z0-9\-_@.\/]', '', $key);
$key = preg_replace('[^a-zA-Z0-9\-_@.\/]', '', $key);
//create a token for the key submitted
$token = [
'name'=>hash_hmac('sha256', $key, bin2hex(random_bytes(32))),
'hash'=>hash_hmac('sha256', $key, bin2hex(random_bytes(32))),
'validated'=>false
];
$token = [
'name' => hash_hmac('sha256', $key, bin2hex(random_bytes(32))),
'hash' => hash_hmac('sha256', $key, bin2hex(random_bytes(32))),
'validated' => false,
];
//save in the token session array
$_SESSION['tokens'][$key][] = $token;
$_SESSION['tokens'][$key][] = $token;
//send the hash
return $token;
}
/**
* validate the token
* @var string $key
* @var string $value
*/
public function validate($key, $value = '') {
//allow only specific characters
$key = preg_replace('[^a-zA-Z0-9]', '', $key);
//get the token name
if (!empty($_SESSION['tokens']) && is_array($_SESSION['tokens'][$key]) && @sizeof($_SESSION['tokens'][$key]) != 0) {
foreach ($_SESSION['tokens'][$key] as $t => $token) {
$token_name = $token['name'];
if (isset($_REQUEST[$token_name])) {
$value = $_REQUEST[$token_name];
break;
}
}
}
//limit the value to specific characters
$value = preg_replace('[^a-zA-Z0-9]', '', $value);
//compare the hashed tokens
if (!empty($_SESSION['tokens']) && is_array($_SESSION['tokens'][$key]) && @sizeof($_SESSION['tokens'][$key]) != 0) {
foreach ($_SESSION['tokens'][$key] as $t => $token) {
if (hash_equals($token['hash'], $value)) {
$_SESSION['tokens'][$key][$t]['validated'] = true;
return true;
}
}
}
return false;
return $token;
}
@@ -124,6 +88,44 @@ class token {
}
}
/**
* validate the token
*
* @var string $key
* @var string $value
*/
public function validate($key, $value = '') {
//allow only specific characters
$key = preg_replace('[^a-zA-Z0-9]', '', $key);
//get the token name
if (!empty($_SESSION['tokens']) && is_array($_SESSION['tokens'][$key]) && @sizeof($_SESSION['tokens'][$key]) != 0) {
foreach ($_SESSION['tokens'][$key] as $t => $token) {
$token_name = $token['name'];
if (isset($_REQUEST[$token_name])) {
$value = $_REQUEST[$token_name];
break;
}
}
}
//limit the value to specific characters
$value = preg_replace('[^a-zA-Z0-9]', '', $value);
//compare the hashed tokens
if (!empty($_SESSION['tokens']) && is_array($_SESSION['tokens'][$key]) && @sizeof($_SESSION['tokens'][$key]) != 0) {
foreach ($_SESSION['tokens'][$key] as $t => $token) {
if (hash_equals($token['hash'], $value)) {
$_SESSION['tokens'][$key][$t]['validated'] = true;
return true;
}
}
}
return false;
}
}
/*
@@ -147,5 +149,3 @@ echo " <input type='hidden' name='".$token['name']."' value='".$token['hash'].
//note: can use $_SERVER['PHP_SELF'] instead of actual file path
*/
?>

View File

@@ -25,54 +25,60 @@
Matthew Vale <github@mafoo.org>
*/
class tones {
class tones {
/**
* declare private variables
*/
private $music_list;
private $recordings_list;
private $default_tone_label;
private $database;
/**
* declare private variables
*/
private $music_list;
private $recordings_list;
private $default_tone_label;
private $database;
/**
* called when the object is created
*/
public function __construct(array $setting_array = []) {
//add multi-lingual support
$language = new text;
$text = $language->get();
/**
* Constructor for the class.
*
* This method initializes the object with setting_array and session data.
*
* @param array $setting_array An optional array of settings to override default values. Defaults to [].
*/
public function __construct(array $setting_array = []) {
//add multi-lingual support
$language = new text;
$text = $language->get();
//connect to the database
$this->database = $setting_array['database'] ?? database::new();
}
/**
* tones_list function
*
* @return array
*/
public function tones_list() {
//get the tones
$sql = "select * from v_vars ";
$sql .= "where var_category = 'Tones' ";
$sql .= "order by var_name asc ";
$tones = $this->database->select($sql, null, 'all');
if (!empty($tones)) {
foreach ($tones as $tone) {
$tone = $tone['var_name'];
if (isset($text['label-'.$tone])) {
$label = $text['label-'.$tone];
}
else {
$label = $tone;
}
$tone_list[$tone] = $label;
}
}
unset($sql, $tones, $tone);
//return the tones
return $tone_list ?? [];
}
//connect to the database
$this->database = $setting_array['database'] ?? database::new();
}
/**
* Retrieves a list of tone names with their corresponding labels.
*
* This method fetches tone data from the database and formats it for display.
*
* @return array An array of tone names as keys and their labels as values. If no tones are found, an empty array
* is returned.
*/
public function tones_list() {
//get the tones
$sql = "select * from v_vars ";
$sql .= "where var_category = 'Tones' ";
$sql .= "order by var_name asc ";
$tones = $this->database->select($sql, null, 'all');
if (!empty($tones)) {
foreach ($tones as $tone) {
$tone = $tone['var_name'];
if (isset($text['label-' . $tone])) {
$label = $text['label-' . $tone];
} else {
$label = $tone;
}
$tone_list[$tone] = $label;
}
}
unset($sql, $tones, $tone);
//return the tones
return $tone_list ?? [];
}
}

View File

@@ -3,18 +3,26 @@
/*
* user class - used to store user groups, permissions, and other values
*/
class user {
public $domain_uuid;
public $domain_name;
public $username;
public $user_email;
public $contact_uuid;
private $database;
public $domain_uuid;
public $domain_name;
private $user_uuid;
private $permissions;
private $groups;
public $username;
public $user_email;
public $contact_uuid;
/**
* Constructor for the class.
*
* This method initializes the object with setting_array and session data.
*
* @param array $setting_array An optional array of settings to override default values. Defaults to [].
*/
public function __construct(database $database, $domain_uuid, $user_uuid) {
//set the database variable
@@ -30,7 +38,7 @@ class user {
$this->user_uuid = $user_uuid;
}
//set the user groups, permission and details
//set the user groups, permission, and details
if (isset($domain_uuid) && is_uuid($domain_uuid) && isset($user_uuid) && is_uuid($user_uuid)) {
$this->set_groups();
$this->set_permissions();
@@ -41,6 +49,16 @@ class user {
/*
* set_details method sets the user assigned details
*/
/**
* Sets the user details based on the domain UUID and user UUID.
*
* This method queries the database to retrieve the user's details,
* including their domain name, username, email address, and contact UUID.
*
* @access public
*
* @return bool True if the query is successful, false otherwise.
*/
public function set_details() {
$sql = "select d.domain_name, u.username, u.user_email, u.contact_uuid ";
$sql .= "from v_users as u, v_domains as d ";
@@ -62,6 +80,11 @@ class user {
/*
* get_user_uuid method gets the user_uuid
*/
/**
* Retrieves the user's UUID.
*
* @return string The user's unique identifier in UUID format.
*/
public function get_user_uuid() {
return $this->user_uuid;
}
@@ -69,31 +92,55 @@ class user {
/*
* set_permissions method sets the user assigned permissions
*/
public function set_permissions() {
$this->permissions = new permissions($this->database, $this->domain_uuid, $this->user_uuid);
}
/*
* get_permissions method gets the user assigned permissions
*/
/**
* Retrieves the permissions associated with this entity.
*
* @return array An array of permission objects or identifiers.
* @access public
*/
public function get_permissions() {
return $this->permissions->get_permissions();
}
/*
* get_permissions method gets the user assigned permissions
*/
/**
* Sets the user's permissions.
*
* @access public
* @return void
*/
public function set_permissions() {
$this->permissions = new permissions($this->database, $this->domain_uuid, $this->user_uuid);
}
/*
* set_groups method sets the user assigned groups
*/
public function set_groups() {
$this->groups = new groups($this->database, $this->domain_uuid, $this->user_uuid);
/**
* Retrieves the user's groups.
*
* @return array An array of group objects that the user belongs to.
*/
public function get_groups() {
return $this->groups->get_groups();
}
/*
* get_groups method gets the user assigned groups
*/
public function get_groups() {
return $this->groups->get_groups();
/**
* Sets the user's group assignments.
*
* @return void
*/
public function set_groups() {
$this->groups = new groups($this->database, $this->domain_uuid, $this->user_uuid);
}
}
?>

View File

@@ -1,10 +1,17 @@
<?php
/*
* Filename.......: class_vcard.php
* Author.........: Troy Wolf [troy@troywolf.com]
* Last Modified..: 2005/07/14 13:30:00
* Description....: A class to generate vCards for contact data.
*/
/**
* A class to generate vCards for contact data.
*
* @author Troy Wolf [troy@troywolf.com]
*/
class vcard {
var $log;
var $data; //array of this vcard's contact data
@@ -14,51 +21,54 @@ class vcard {
var $card;
/**
* Called when the object is created
* Constructor for initializing the object.
*
* @access public
* @return bool True on successful initialization.
*/
public function __construct() {
$this->log = "New vcard() called<br />";
$this->data = array(
"display_name"=>null
,"first_name"=>null
,"last_name"=>null
,"additional_name"=>null
,"name_prefix"=>null
,"name_suffix"=>null
,"nickname"=>null
,"title"=>null
,"role"=>null
,"department"=>null
,"company"=>null
,"work_po_box"=>null
,"work_extended_address"=>null
,"work_address"=>null
,"work_city"=>null
,"work_state"=>null
,"work_postal_code"=>null
,"work_country"=>null
,"home_po_box"=>null
,"home_extended_address"=>null
,"home_address"=>null
,"home_city"=>null
,"home_state"=>null
,"home_postal_code"=>null
,"home_country"=>null
,"voice_tel"=>null
,"work_tel"=>null
,"home_tel"=>null
,"cell_tel"=>null
,"fax_tel"=>null
,"pager_tel"=>null
,"email1"=>null
,"email2"=>null
,"url"=>null
,"photo"=>null
,"birthday"=>null
,"timezone"=>null
,"sort_string"=>null
,"note"=>null
);
$this->log = "New vcard() called<br />";
$this->data = [
"display_name" => null
, "first_name" => null
, "last_name" => null
, "additional_name" => null
, "name_prefix" => null
, "name_suffix" => null
, "nickname" => null
, "title" => null
, "role" => null
, "department" => null
, "company" => null
, "work_po_box" => null
, "work_extended_address" => null
, "work_address" => null
, "work_city" => null
, "work_state" => null
, "work_postal_code" => null
, "work_country" => null
, "home_po_box" => null
, "home_extended_address" => null
, "home_address" => null
, "home_city" => null
, "home_state" => null
, "home_postal_code" => null
, "home_country" => null
, "voice_tel" => null
, "work_tel" => null
, "home_tel" => null
, "cell_tel" => null
, "fax_tel" => null
, "pager_tel" => null
, "email1" => null
, "email2" => null
, "url" => null
, "photo" => null
, "birthday" => null
, "timezone" => null
, "sort_string" => null
, "note" => null,
];
return true;
}
@@ -66,109 +76,169 @@ class vcard {
build() method checks all the values, builds appropriate defaults for
missing values, generates the vcard data string.
*/
/**
* Downloads the vCard data as a file.
*
* @access public
* @return bool True on successful download, false otherwise.
*/
function download() {
$this->log .= "vcard download() called<br />";
if (!$this->card) {
$this->build();
}
if (!$this->filename) {
$this->filename = trim($this->data['display_name']);
}
$this->filename = str_replace(" ", "_", $this->filename);
header("Content-type: text/directory");
header("Content-Disposition: attachment; filename=" . $this->filename . ".vcf");
header("Pragma: public");
echo $this->card;
return true;
}
/*
download() method streams the vcard to the browser client.
*/
/**
* Builds the vCard.
*
* @access public
* @return string The built vCard as a string.
*/
function build() {
$this->log .= "vcard build() called<br />";
/*
For many of the values, if they are not passed in, we set defaults or
build them based on other values.
*/
if (!$this->class) { $this->class = "PUBLIC"; }
if (!$this->data['display_name']) {
$this->data['display_name'] = trim($this->data['first_name']." ".$this->data['last_name']);
if (!$this->class) {
$this->class = "PUBLIC";
}
if (!$this->data['display_name']) {
$this->data['display_name'] = trim($this->data['first_name'] . " " . $this->data['last_name']);
}
if (!$this->data['sort_string']) {
$this->data['sort_string'] = $this->data['last_name'];
}
if (!$this->data['sort_string']) {
$this->data['sort_string'] = $this->data['company'];
}
if (!$this->data['timezone']) {
$this->data['timezone'] = date("O");
}
if (!$this->revision_date) {
$this->revision_date = date('Y-m-d H:i:s');
}
if (!$this->data['sort_string']) { $this->data['sort_string'] = $this->data['last_name']; }
if (!$this->data['sort_string']) { $this->data['sort_string'] = $this->data['company']; }
if (!$this->data['timezone']) { $this->data['timezone'] = date("O"); }
if (!$this->revision_date) { $this->revision_date = date('Y-m-d H:i:s'); }
$this->card = "BEGIN:VCARD\r\n";
$this->card .= "VERSION:3.0\r\n";
//$this->card .= "CLASS:".$this->class."\r\n";
//$this->card .= "PRODID:-//class_vcard from TroyWolf.com//NONSGML Version 1//EN\r\n";
// $this->card .= "REV:".$this->revision_date."\r\n";
$this->card .= "FN:".$this->data['display_name']."\r\n";
$this->card .= "FN:" . $this->data['display_name'] . "\r\n";
$this->card .= "N:";
$this->card .= $this->data['last_name'].";";
$this->card .= $this->data['last_name'] . ";";
$this->card .= $this->data['first_name'];
if (!empty($this->data['additional_name'])) {
$this->card .= ";".$this->data['additional_name'];
$this->card .= ";" . $this->data['additional_name'];
}
if (!empty($this->data['name_prefix'])) {
$this->card .= ";".$this->data['name_prefix'];
$this->card .= ";" . $this->data['name_prefix'];
}
if (!empty($this->data['name_suffix'])) {
$this->card .= ";".$this->data['name_suffix'];
$this->card .= ";" . $this->data['name_suffix'];
}
$this->card .= "\r\n";
if ($this->data['nickname']) { $this->card .= "NICKNAME:".$this->data['contact_nickname']."\r\n"; }
if ($this->data['title']) { $this->card .= "TITLE:".$this->data['title']."\r\n"; }
if ($this->data['company']) { $this->card .= "ORG:".$this->data['company']; }
if ($this->data['department']) { $this->card .= ";".$this->data['department']; }
if ($this->data['nickname']) {
$this->card .= "NICKNAME:" . $this->data['contact_nickname'] . "\r\n";
}
if ($this->data['title']) {
$this->card .= "TITLE:" . $this->data['title'] . "\r\n";
}
if ($this->data['company']) {
$this->card .= "ORG:" . $this->data['company'];
}
if ($this->data['department']) {
$this->card .= ";" . $this->data['department'];
}
$this->card .= "\r\n";
$vcard_address_type_values = array('work','home','dom','intl','postal','parcel','pref');
$vcard_address_type_values = ['work', 'home', 'dom', 'intl', 'postal', 'parcel', 'pref'];
foreach ($vcard_address_type_values as $vcard_address_type_value) {
if (!empty($this->data[$vcard_address_type_value.'_po_box'])
|| !empty($this->data[$vcard_address_type_value.'_extended_address'])
|| !empty($this->data[$vcard_address_type_value.'_address'])
|| !empty($this->data[$vcard_address_type_value.'_city'])
|| !empty($this->data[$vcard_address_type_value.'_state'])
|| !empty($this->data[$vcard_address_type_value.'_postal_code'])
|| !empty($this->data[$vcard_address_type_value.'_country'])) {
$this->card .= "ADR;TYPE=".$vcard_address_type_value.":";
if (!empty($this->data[$vcard_address_type_value.'_po_box'])) {
$this->card .= $this->data[$vcard_address_type_value.'_po_box'].";";
if (!empty($this->data[$vcard_address_type_value . '_po_box'])
|| !empty($this->data[$vcard_address_type_value . '_extended_address'])
|| !empty($this->data[$vcard_address_type_value . '_address'])
|| !empty($this->data[$vcard_address_type_value . '_city'])
|| !empty($this->data[$vcard_address_type_value . '_state'])
|| !empty($this->data[$vcard_address_type_value . '_postal_code'])
|| !empty($this->data[$vcard_address_type_value . '_country'])) {
$this->card .= "ADR;TYPE=" . $vcard_address_type_value . ":";
if (!empty($this->data[$vcard_address_type_value . '_po_box'])) {
$this->card .= $this->data[$vcard_address_type_value . '_po_box'] . ";";
}
if (!empty($this->data[$vcard_address_type_value.'_extended_address'])) {
$this->card .= $this->data[$vcard_address_type_value.'_extended_address'].";";
if (!empty($this->data[$vcard_address_type_value . '_extended_address'])) {
$this->card .= $this->data[$vcard_address_type_value . '_extended_address'] . ";";
}
if (!empty($this->data[$vcard_address_type_value.'_address'])) {
$this->card .= $this->data[$vcard_address_type_value.'_address'].";";
if (!empty($this->data[$vcard_address_type_value . '_address'])) {
$this->card .= $this->data[$vcard_address_type_value . '_address'] . ";";
}
if (!empty($this->data[$vcard_address_type_value.'_city'])) {
$this->card .= $this->data[$vcard_address_type_value.'_city'].";";
if (!empty($this->data[$vcard_address_type_value . '_city'])) {
$this->card .= $this->data[$vcard_address_type_value . '_city'] . ";";
}
if (!empty($this->data[$vcard_address_type_value.'_state'])) {
$this->card .= $this->data[$vcard_address_type_value.'_state'].";";
if (!empty($this->data[$vcard_address_type_value . '_state'])) {
$this->card .= $this->data[$vcard_address_type_value . '_state'] . ";";
}
if (!empty($this->data[$vcard_address_type_value.'_postal_code'])) {
$this->card .= $this->data[$vcard_address_type_value.'_postal_code'].";";
if (!empty($this->data[$vcard_address_type_value . '_postal_code'])) {
$this->card .= $this->data[$vcard_address_type_value . '_postal_code'] . ";";
}
if (!empty($this->data[$vcard_address_type_value.'_country'])) {
$this->card .= $this->data[$vcard_address_type_value.'_country']."";
if (!empty($this->data[$vcard_address_type_value . '_country'])) {
$this->card .= $this->data[$vcard_address_type_value . '_country'] . "";
}
$this->card .= "\r\n";
}
}
if ($this->data['email1']) { $this->card .= "EMAIL;PREF=1:".$this->data['email1']."\r\n"; }
if ($this->data['email2']) { $this->card .= "EMAIL;PREF=2:".$this->data['email2']."\r\n"; }
if ($this->data['voice_tel']) { $this->card .= "TEL;TYPE=voice:".$this->data['voice_tel']."\r\n"; }
if ($this->data['work_tel']) { $this->card .= "TEL;TYPE=work:".$this->data['work_tel']."\r\n"; }
if ($this->data['home_tel']) { $this->card .= "TEL;TYPE=home:".$this->data['home_tel']."\r\n"; }
if ($this->data['cell_tel']) { $this->card .= "TEL;TYPE=cell:".$this->data['cell_tel']."\r\n"; }
if ($this->data['fax_tel']) { $this->card .= "TEL;TYPE=fax:".$this->data['fax_tel']."\r\n"; }
if ($this->data['pager_tel']) { $this->card .= "TEL;TYPE=pager:".$this->data['pager_tel']."\r\n"; }
if ($this->data['url']) { $this->card .= "URL:".$this->data['url']."\r\n"; }
if ($this->data['birthday']) { $this->card .= "BDAY:".$this->data['birthday']."\r\n"; }
if ($this->data['role']) { $this->card .= "ROLE:".$this->data['role']."\r\n"; }
if ($this->data['note']) { $this->card .= "NOTE:".$this->data['note']."\r\n"; }
$this->card .= "TZ:".$this->data['timezone']."\r\n";
if ($this->data['email1']) {
$this->card .= "EMAIL;PREF=1:" . $this->data['email1'] . "\r\n";
}
if ($this->data['email2']) {
$this->card .= "EMAIL;PREF=2:" . $this->data['email2'] . "\r\n";
}
if ($this->data['voice_tel']) {
$this->card .= "TEL;TYPE=voice:" . $this->data['voice_tel'] . "\r\n";
}
if ($this->data['work_tel']) {
$this->card .= "TEL;TYPE=work:" . $this->data['work_tel'] . "\r\n";
}
if ($this->data['home_tel']) {
$this->card .= "TEL;TYPE=home:" . $this->data['home_tel'] . "\r\n";
}
if ($this->data['cell_tel']) {
$this->card .= "TEL;TYPE=cell:" . $this->data['cell_tel'] . "\r\n";
}
if ($this->data['fax_tel']) {
$this->card .= "TEL;TYPE=fax:" . $this->data['fax_tel'] . "\r\n";
}
if ($this->data['pager_tel']) {
$this->card .= "TEL;TYPE=pager:" . $this->data['pager_tel'] . "\r\n";
}
if ($this->data['url']) {
$this->card .= "URL:" . $this->data['url'] . "\r\n";
}
if ($this->data['birthday']) {
$this->card .= "BDAY:" . $this->data['birthday'] . "\r\n";
}
if ($this->data['role']) {
$this->card .= "ROLE:" . $this->data['role'] . "\r\n";
}
if ($this->data['note']) {
$this->card .= "NOTE:" . $this->data['note'] . "\r\n";
}
$this->card .= "TZ:" . $this->data['timezone'] . "\r\n";
$this->card .= "END:VCARD";
}
/*
download() method streams the vcard to the browser client.
*/
function download() {
$this->log .= "vcard download() called<br />";
if (!$this->card) { $this->build(); }
if (!$this->filename) { $this->filename = trim($this->data['display_name']); }
$this->filename = str_replace(" ", "_", $this->filename);
header("Content-type: text/directory");
header("Content-Disposition: attachment; filename=".$this->filename.".vcf");
header("Pragma: public");
echo $this->card;
return true;
}
}

View File

@@ -2,120 +2,80 @@
/**
*
*
* @author MaximAL
* @since 2019-02-13 Added `$onePhase` parameters to get only positive waveform data and image
* @since 2018-10-22 Added `getWaveformData()` method and `$soxCommand` configuration
* @since 2016-11-21
* @date 2016-11-21
* @time 19:08
* @link http://maximals.ru
* @link http://sijeko.ru
* @link https://github.com/maximal/audio-waveform-php
* @author MaximAL
* @since 2019-02-13 Added `$onePhase` parameters to get only positive waveform data and image
* @since 2018-10-22 Added `getWaveformData()` method and `$soxCommand` configuration
* @since 2016-11-21
* @date 2016-11-21
* @time 19:08
* @link http://maximals.ru
* @link http://sijeko.ru
* @link https://github.com/maximal/audio-waveform-php
* @copyright © MaximAL, Sijeko 2016-2019
*
* @modified fusionate
* @since 2024-02-07 Added option to return image in base64 format by setting $filename to 'base64'
* @since 2024-02-08 Added `$singleAxis` parameter to combine channels (if stereo) into single axis
* @since 2024-02-08 Added `$colorA` and `$colorB` parameters to allow different colors for each channel
* @since 2024-02-08 Rename `$onePhase` parameter to `$singlePhase` and change to public static variable for class
* @since 2024-02-08 Modified singleAxis so channel 2 would display as negative waveform data when singlePhase enabled
* @modified fusionate
* @since 2024-02-07 Added option to return image in base64 format by setting $filename to 'base64'
* @since 2024-02-08 Added `$singleAxis` parameter to combine channels (if stereo) into single axis
* @since 2024-02-08 Added `$colorA` and `$colorB` parameters to allow different colors for each channel
* @since 2024-02-08 Rename `$onePhase` parameter to `$singlePhase` and change to public static variable for class
* @since 2024-02-08 Modified singleAxis so channel 2 would display as negative waveform data when singlePhase
* enabled
*
*
*/
namespace maximal\audio;
use Exception;
/**
* Waveform class allows you to get waveform data and images from audio files
*
* @package maximal\audio
*/
class Waveform
{
protected $filename;
protected $info;
protected $channels;
protected $samples;
protected $sampleRate;
protected $duration;
class Waveform {
public static $linesPerPixel = 8;
public static $samplesPerLine = 512;
public static $singlePhase; // set `true` to get positive waveform phase only, `false` to get both positive and negative waveform phases
public static $singleAxis; // combine double or single phases to use same axis
public static $singlePhase;
public static $singleAxis;
public static $color = [95, 95, 95, 0.5];
public static $colorA;
public static $colorB;
public static $backgroundColor = [245, 245, 245, 1];
public static $axisColor = [0, 0, 0, 0.1]; // set `true` to get positive waveform phase only, `false` to get both positive and negative waveform phases
public static $soxCommand = 'sox'; // combine double or single phases to use same axis
// Colors in CSS `rgba(red, green, blue, opacity)` format
public static $color = [95, 95, 95, 0.5];
public static $colorA; // color of left channel (1)
public static $colorB; // color of right channel (2)
public static $backgroundColor = [245, 245, 245, 1];
public static $axisColor = [0, 0, 0, 0.1];
protected $filename;
protected $info; // color of left channel (1)
protected $channels; // color of right channel (2)
protected $samples;
protected $sampleRate;
// SoX command: 'sox', '/usr/local/bin/sox' etc
public static $soxCommand = 'sox';
protected $duration;
public function __construct($filename)
{
/**
* Initializes a new instance of this class with the specified filename.
*
* @param string $filename The name of the file associated with this instance.
*
* @access public
*/
public function __construct($filename) {
$this->filename = $filename;
}
public function getInfo()
{
$out = null;
$ret = null;
exec(self::$soxCommand . ' --i ' . escapeshellarg($this->filename) . ' 2>&1', $out, $ret);
$str = implode('|', $out);
$match = null;
if (preg_match('/Channels?\s*\:\s*(\d+)/ui', $str, $match)) {
$this->channels = intval($match[1]);
}
$match = null;
if (preg_match('/Sample\s*Rate\s*\:\s*(\d+)/ui', $str, $match)) {
$this->sampleRate = intval($match[1]);
}
$match = null;
if (preg_match('/Duration.*[^\d](\d+)\s*samples?/ui', $str, $match)) {
$this->samples = intval($match[1]);
}
if ($this->samples && $this->sampleRate) {
$this->duration = 1.0 * $this->samples / $this->sampleRate;
}
if ($ret !== 0) {
throw new \Exception('Failed to get audio info.' . PHP_EOL . 'Error: ' . implode(PHP_EOL, $out) . PHP_EOL);
}
}
public function getSampleRate()
{
if (!$this->sampleRate) {
$this->getInfo();
}
return $this->sampleRate;
}
public function getChannels()
{
if (!$this->channels) {
$this->getInfo();
}
return $this->channels;
}
public function getSamples()
{
if (!$this->samples) {
$this->getInfo();
}
return $this->samples;
}
public function getDuration()
{
/**
* Retrieves the duration of the current media file.
*
* If the duration has not been retrieved yet, it will be fetched from the media server.
*
* @return float The duration of the media file in seconds.
*
* @access public
*/
public function getDuration() {
if (!$this->duration) {
$this->getInfo();
}
@@ -124,14 +84,15 @@ class Waveform
/**
* Get waveform from the audio file.
*
* @param string $filename Image file name
* @param int $width Width of the image file in pixels
* @param int $height Height of the image file in pixels
* @param int $width Width of the image file in pixels
* @param int $height Height of the image file in pixels
*
* @return bool Returns `true` on success or `false` on failure, when generating an image file, or a base64 string.
* @throws \Exception
*/
public function getWaveform($filename, $width, $height)
{
public function getWaveform($filename, $width, $height) {
// Calculating parameters
$needChannels = $this->getChannels() > 1 ? 2 : 1;
$data = $this->getWaveformData($width, self::$singlePhase ?? false);
@@ -159,7 +120,7 @@ class Waveform
$center1 = $center2 = $height / 2;
} else {
if (self::$singlePhase ?? false) {
$center1 = $needChannels === 2 ? $height / 2 - 1: $height - 1;
$center1 = $needChannels === 2 ? $height / 2 - 1 : $height - 1;
$center2 = $needChannels === 2 ? $height - 1 : null;
} else {
$center1 = $needChannels === 2 ? ($height / 2 - 1) / 2 : $height / 2;
@@ -218,14 +179,31 @@ class Waveform
}
}
/**
* Retrieves a collection of channels.
*
* If no channels have been loaded yet, the {@link getInfo()} method is called to load them first.
*
* @return array A collection of channel objects.
*
* @access public
*/
public function getChannels() {
if (!$this->channels) {
$this->getInfo();
}
return $this->channels;
}
/**
* Get waveform data from the audio file.
*
* @param int $width Desired width of the image file in pixels
*
* @return array
* @throws \Exception
*/
public function getWaveformData($width)
{
public function getWaveformData($width) {
// Calculating parameters
$needChannels = $this->getChannels() > 1 ? 2 : 1;
$samplesPerPixel = self::$samplesPerLine * self::$linesPerPixel;
@@ -249,7 +227,7 @@ class Waveform
$pipes = null;
$proc = proc_open($command, $outputs, $pipes);
if (!$proc) {
throw new \Exception('Failed to run `sox` command');
throw new Exception('Failed to run `sox` command');
}
$lines1 = [];
@@ -260,26 +238,26 @@ class Waveform
$channel2 = [];
foreach ($data as $index => $sample) {
if ($needChannels === 2 && $index % 2 === 0) {
$channel2 []= $sample;
$channel2 [] = $sample;
} else {
$channel1 []= $sample;
$channel1 [] = $sample;
}
}
if (self::$singlePhase ?? false) {
// Rectifying to get positive values only
$lines1 []= abs(min($channel1));
$lines1 []= abs(max($channel1));
$lines1 [] = abs(min($channel1));
$lines1 [] = abs(max($channel1));
if ($needChannels === 2) {
$lines2 []= abs(min($channel2));
$lines2 []= abs(max($channel2));
$lines2 [] = abs(min($channel2));
$lines2 [] = abs(max($channel2));
}
} else {
// Two phases
$lines1 []= min($channel1);
$lines1 []= max($channel1);
$lines1 [] = min($channel1);
$lines1 [] = max($channel1);
if ($needChannels === 2) {
$lines2 []= min($channel2);
$lines2 []= max($channel2);
$lines2 [] = min($channel2);
$lines2 [] = max($channel2);
}
}
}
@@ -288,14 +266,92 @@ class Waveform
$ret = proc_close($proc);
if ($ret !== 0) {
throw new \Exception('Failed to run `sox` command. Error:' . PHP_EOL . $err);
throw new Exception('Failed to run `sox` command. Error:' . PHP_EOL . $err);
}
return ['lines1' => $lines1, 'lines2' => $lines2];
}
public static function rgbaToColor($img, $rgba)
{
/**
* Retrieves the sample rate associated with this instance.
*
* If the sample rate has not been previously retrieved, it will be obtained
* by calling getInfo(). The sample rate is then cached for future retrieval.
*
* @return int|null The sample rate in Hz, or null if unable to retrieve the information.
*
* @access public
*/
public function getSampleRate() {
if (!$this->sampleRate) {
$this->getInfo();
}
return $this->sampleRate;
}
/**
* Retrieves information about the audio file associated with this instance.
*
* @access public
*/
public function getInfo() {
$out = null;
$ret = null;
exec(self::$soxCommand . ' --i ' . escapeshellarg($this->filename) . ' 2>&1', $out, $ret);
$str = implode('|', $out);
$match = null;
if (preg_match('/Channels?\s*\:\s*(\d+)/ui', $str, $match)) {
$this->channels = intval($match[1]);
}
$match = null;
if (preg_match('/Sample\s*Rate\s*\:\s*(\d+)/ui', $str, $match)) {
$this->sampleRate = intval($match[1]);
}
$match = null;
if (preg_match('/Duration.*[^\d](\d+)\s*samples?/ui', $str, $match)) {
$this->samples = intval($match[1]);
}
if ($this->samples && $this->sampleRate) {
$this->duration = 1.0 * $this->samples / $this->sampleRate;
}
if ($ret !== 0) {
throw new Exception('Failed to get audio info.' . PHP_EOL . 'Error: ' . implode(PHP_EOL, $out) . PHP_EOL);
}
}
/**
* Retrieves a collection of sample data.
*
* If no samples have been retrieved yet, this method will call getInfo() to populate the internal samples list.
*
* @return int The collection of sample data.
*
* @access public
*/
public function getSamples() {
if (!$this->samples) {
$this->getInfo();
}
return $this->samples;
}
/**
* Converts an RGBA color to a PHP image color with alpha channel.
*
* @param resource $img The PHP image resource to convert the color for.
* @param array $rgba An array containing the red, green, blue and alpha values of the color.
*
* @return int The allocated color index.
*
* @access public
* @static
*/
public static function rgbaToColor($img, $rgba) {
return imagecolorallocatealpha($img, $rgba[0], $rgba[1], $rgba[2], round((1 - $rgba[3]) * 127));
}
}

View File

@@ -1,18 +1,20 @@
<?php
/**
* xml class
*/
class xml {
/**
* xml class
* Sanitizes a string by removing any PHP-style placeholders and encoding special characters.
*
* @param string $string The input string to be sanitized.
*
* @return string The sanitized string with special characters encoded.
*/
class xml {
/**
* Escapes xml special characters to html entities and sanitze switch special chars.
* @param mixed $string
* @return void
*/
static function sanitize($string) {
$string = preg_replace('/\$\{[^}]+\}/', '', $string);
return htmlspecialchars($string, ENT_XML1);
}
static function sanitize($string) {
$string = preg_replace('/\$\{[^}]+\}/', '', $string);
return htmlspecialchars($string, ENT_XML1);
}
}