Files
fusionpbx/resources/classes/event_socket.php
FusionPBX dda18481ec Refactor PHP code (#7574)
* Use settings-get method
- get default, domain and user settings
- Replace _SESSION

* Simplify get domain paging

* Change isset using empty

* Fix token name and hash

* Add new default settings category: contact, name: default_sort_column, and default_sort_order

* Update app_config.php

* Update footer.php

* Fix require.php and core/dashboard/index.php (#7563)

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Fix require.php and core/dashboard/index.php

* Update destinations.php

* Update permission.php

* Update require.php

---------

Co-authored-by: FusionPBX <markjcrane@gmail.com>
Co-authored-by: FusionPBX <mark@fusionpbx.com>

* Update header.php

* Use settings get classes (#7567)

* access_control

* azure

* azure

* basic_operator_panel

* bridges

* call_block

* call_broadcast

* call_center

* call_flows

* call_forward

* call_recordings

* do_not_disturb

* feature_event_notify

* follow_me

* remove unused object properties

* fix esl command

* fix esl command

* conference_centers

* conference_centers - remove whitespace

* conference_controls

* conference_profiles

* conference_profiles

* Delete core/websockets/resources/classes/socket_exception.php.original~

* Delete core/websockets/resources/classes/websocket_server.php.original~

* conferences

* destinations

* device

* dialplan

* email_queue

* event_guard

* extension_settings

* extension

* fax

* fax_queue

* fifo

* gateways

* ivr_menu

* modules

* switch_music_on_hold

* number_translations

* phrases

* pin_numbers

* provision

* switch_recordings

* registrations

* ring_groups

* sip_profiles

* sofia_global_settings

* streams

* presence

* switch_files

* time_conditions

* vars

* voicemail_greetings

* voicemail

* ringbacks

* contacts

* xml_cdr

* authentication

* dashboard

* default_settings

* domain_settings

* email_templates

* permission

* user_logs

* user_settings

* users

* button

* cache

* captcha

* remove cli_option

* remove directory.php for switch_directory class

* email

* file

* groups

* event_socket use config object

* Use intval to give an integer port

* switch_settings

* tones

* fix object used before initialization

* menu

* fix copy paste error for switch_files.php

* always include require.php for framework files

* Fix missing properties

* set the action

* Use the $database object

* Add missing class properties

* Fix the domain_name

* Use public scope for domain_uuid and domain_name

* Add missing parameters

* Correct the user_uuid parameter

* Add json_validate and use it in the dashboard
update indentation on functions.php

* Intialize the active_registrations variable

* Define the $parameters

* Set a default value for user_setting_enabled

* Add condition domain_uuid not empty

* Add not empty condition for domain_uuid

* Declare the global variables

* Update how the defaults are set use ??

* Use ?? to set the default values

* Update call_center_queue_edit.php

* Prevent an error

* Add domain_name property

* Fix the null coalescing operator

* Removed domain_uuid from the URL

* Change condition to check sip_profile_domain_name

* Refactor domain_uuid declaration and comments

Removed redundant domain_uuid declaration and updated comments.

* Account for an empty value

* Refactor constructor to use settings array

Updated constructor to accept settings array for domain UUID and database initialization.

* Refactor xml_cdr.php to improve variable organization

Removed duplicate domain_uuid declaration and reorganized private variables for better structure.

* Enhance transcription button logic and icon display

Updated transcription button visibility conditions and improved application icon handling in the call flow summary.

* Refactor settings initialization in domains.php

Updated settings initialization to include domain_uuid and user_uuid.

* Modify domain change condition in require.php

Updated condition to check if 'domain_change' is not empty before proceeding.

* Set default_setting_enabled to true by default

* Enhance domain UUID check in access controls

* Enhance domain UUID check in settings list

* Refactor category display logic in vars.php

* Simplify list row URL generation

Removed domain UUID check from list row URL construction.

* Refactor module category display logic

* Fix SQL query by removing parameters variable

* Initialize result_count variable for call recordings

* Refactor leg variable usage in xml_cdr_details.php

* Update conference_room_edit.php

* Change GET to REQUEST for order and search variables

* Set timezone and SQL time format in recordings.php

Added timezone and SQL time format settings.

* Set default for ring group greeting

* Improve domain UUID check in stream listing

* Handle null voicemail_option_param safely

* Add file existence check for greeting files

Check if greeting file exists before getting size and date.

* Improve domain UUID check in email templates

* Update FIFO strategy dropdown and description text

* Add multilingual agent descriptions

Added multilingual descriptions for agents in the app_languages.php file.

* Add music on hold descriptions

* Add the chime list description

Updated copyright year from 2024 to 2025.

* Fix domain UUID check and handle email subject decoding

* Add null coalescing for $value in email_test.php

Ensure $value is not null by providing a default empty string.

* Handle undefined dialplan_uuid in input field

* Add translations for 'Status' label in multiple languages

* Fix typo in config instance check

---------

Co-authored-by: frytimo <tim@fusionpbx.com>
2025-10-15 21:24:59 -06:00

321 lines
8.4 KiB
PHP

<?php
class buffer {
private $content;
private $eol;
public function __construct() {
$this->content = '';
$this->eol = "\n";
}
public function append($str) {
$this->content .= $str;
}
public function read_line() {
$ar = explode($this->eol, $this->content, 2);
if (count($ar) != 2) {
return false;
}
$this->content = $ar[1];
return $ar[0];
}
public function read_n($n) {
if (strlen($this->content) < $n) {
return false;
}
$s = substr($this->content, 0, $n);
$this->content = substr($this->content, $n);
return $s;
}
public function read_all($n) {
$tmp = $this->content;
$this->content = '';
return $tmp;
}
}
//$b = new buffer;
//$b->append("hello\nworld\n");
//print($b->read_line());
//print($b->read_line());
/**
* Subscribes to the event socket of the FreeSWITCH (c) Event Socket Server
* @depends buffer::class
*/
class event_socket {
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) {
$this->buffer = new buffer;
$this->fp = $fp;
$this->config = $config ?? config::load();
}
/**
* Ensures a closed connection on destruction of object
*/
public function __destructor() {
$this->close();
}
/**
* Read the event body from the socket
* @return string|false Content body or false if not connected or empty message
* @depends buffer::class
*/
public function read_event() {
if (!$this->connected()) {
return false;
}
$b = $this->buffer;
$content = array();
while (true) {
$line = $b->read_line();
if ($line !== false) {
if ($line === '') {
break;
}
list($key, $value) = explode(':', $line, 2);
$content[trim($key)] = trim($value);
}
if (feof($this->fp)) {
break;
}
$buffer = fgets($this->fp, 1024);
$b->append($buffer);
}
if (array_key_exists('Content-Length', $content)) {
$str = $b->read_n($content['Content-Length']);
if ($str === false) {
while (true) {
if (!$this->connected()) {
break;
}
$buffer = fgets($this->fp, 1024);
$b->append($buffer);
$str = $b->read_n($content['Content-Length']);
if ($str !== false) {
break;
}
}
}
if ($str !== false) {
$content['$'] = $str;
}
}
return $content;
}
/**
* 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>
* @global array $conf Global configuration used in fusionpbx/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 bool Returns true on success or false if not connected
*/
public function connect($host = null, $port = null, $password = null, $timeout_microseconds = 30000) {
//set the event socket variables in the order of
//param passed to func, conf setting, old conf setting, default
$host = $host ?? $this->config->get('switch.event_socket.host', null) ?? $this->config->get('event_socket.ip_address', null) ?? '127.0.0.1';
$port = intval($port ?? $this->config->get('switch.event_socket.port', null) ?? $this->config->get('event_socket.port', null) ?? '8021');
$password = $password ?? $this->config->get('switch.event_socket.password', null) ?? $this->config->get('event_socket.password', null) ?? 'ClueCon';
//if a socket was provided in the constructor then don't create a new one
if ($this->fp === false) {
//open the socket connection
$this->fp = @fsockopen($host, $port, $errno, $errdesc, 3);
}
if (!$this->connected()) {
return false;
}
socket_set_timeout($this->fp, 0, $timeout_microseconds);
socket_set_blocking($this->fp, true);
//wait auth request and send response
while ($this->connected()) {
$event = $this->read_event();
if(($event['Content-Type'] ?? '') === 'auth/request'){
fputs($this->fp, "auth $password\n\n");
break;
}
}
//wait auth response
while ($this->connected()) {
$event = $this->read_event();
if (($event['Content-Type'] ?? '') === 'command/reply') {
if (($event['Reply-Text'] ?? '') === '+OK accepted') {
break;
} else {
$this->close();
}
}
}
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 {
if (!is_resource($this->fp)) {
//not connected to the socket
return false;
}
if (feof($this->fp) === true) {
//not connected to the socket
return false;
}
//connected to the 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){
$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'));
?>