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
+34 -7
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');
?>
+213 -165
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;
}
}
+40 -44
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;
}
}
?>
+128 -107
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
+185 -163
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;
}
}
?>
+30 -21
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";
*/
?>
+89 -49
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
+199 -151
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
+143 -122
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'));
?>
+82 -53
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);
*/
?>
+10 -1
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;
}
}
+55 -18
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
+11 -2
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);
}
}
+257 -153
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");
*/
+1508 -1440
View File
File diff suppressed because it is too large Load Diff
+60 -38
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;
}
}
}
+59 -41
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
+130 -88
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
+167 -131
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');
}
}
+63 -59
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;
}
}
?>
+296 -277
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);
}
}
+84 -60
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);
}
}
}
+400 -386
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;
}
}
+52 -52
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
*/
?>
+53 -47
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 ?? [];
}
}
+65 -18
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);
}
}
?>
+180 -110
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;
}
}
+169 -113
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));
}
}
+15 -13
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);
}
}