diff --git a/app/xml_cdr/resources/classes/xml_cdr.php b/app/xml_cdr/resources/classes/xml_cdr.php new file mode 100644 index 0000000000..9c17357d04 --- /dev/null +++ b/app/xml_cdr/resources/classes/xml_cdr.php @@ -0,0 +1,561 @@ + + Portions created by the Initial Developer are Copyright (C) 2016 + the Initial Developer. All Rights Reserved. + + Contributor(s): + Mark J Crane +*/ + + +/** + * xml_cdr class provides methods for adding cdr records to the database + * + * @method boolean add + */ +if (!class_exists('xml_cdr')) { + class xml_cdr { + + //define variables + public $db; + public $array; + public $debug; + public $fields; + + /** + * Called when the object is created + */ + public function __construct() { + //connect to the database if not connected + if (!$this->db) { + require_once "resources/classes/database.php"; + $database = new database; + $database->connect(); + $this->db = $database->db; + } + } + + /** + * Called when there are no references to a particular object + * unset the variables used in the class + */ + public function __destruct() { + foreach ($this as $key => $value) { + unset($this->$key); + } + } + + + /** + * cdr process logging + */ + public function log($message) { + //save to file system (alternative to a syslog server) + $fp = fopen($_SESSION['server']['temp']['dir'].'/xml_cdr.log', 'a+'); + if (!$fp) { + return; + } + fwrite($fp, $msg); + fclose($fp); + } + + /** + * cdr fields in the database schema + */ + public function fields() { + + $array[] = "uuid"; + $array[] = "domain_uuid"; + $array[] = "extension_uuid"; + $array[] = "domain_name"; + $array[] = "accountcode"; + $array[] = "direction"; + $array[] = "default_language"; + $array[] = "context"; + $array[] = "xml"; + $array[] = "json"; + $array[] = "caller_id_name"; + $array[] = "caller_id_number"; + $array[] = "destination_number"; + $array[] = "start_epoch"; + $array[] = "start_stamp"; + $array[] = "answer_stamp"; + $array[] = "answer_epoch"; + $array[] = "end_epoch"; + $array[] = "end_stamp"; + $array[] = "duration"; + $array[] = "mduration"; + $array[] = "billsec"; + $array[] = "billmsec"; + $array[] = "bridge_uuid"; + $array[] = "read_codec"; + $array[] = "read_rate"; + $array[] = "write_codec"; + $array[] = "write_rate"; + $array[] = "remote_media_ip"; + $array[] = "network_addr"; + $array[] = "recording_file"; + $array[] = "leg"; + $array[] = "pdd_ms"; + $array[] = "rtp_audio_in_mos"; + $array[] = "last_app"; + $array[] = "last_arg"; + $array[] = "cc_side"; + $array[] = "cc_member_uuid"; + $array[] = "cc_queue_joined_epoch"; + $array[] = "cc_queue"; + $array[] = "cc_member_session_uuid"; + $array[] = "cc_agent"; + $array[] = "cc_agent_type"; + $array[] = "waitsec"; + $array[] = "conference_name"; + $array[] = "conference_uuid"; + $array[] = "conference_member_id"; + $array[] = "digits_dialed"; + $array[] = "pin_number"; + $array[] = "hangup_cause"; + $array[] = "hangup_cause_q850"; + $array[] = "sip_hangup_disposition"; + $this->fields($array); + unset($array); + + } + + /** + * save to the database + */ + public function save() { + + $field_count = sizeof($this->fields); + + $sql = "insert into v_xml_cdr ("; + foreach ($this->fields as $field) { + $sql .= "$field, "; + } + $sql .= ")\n"; + $sql .= "values \n"; + $row_count = sizeof($this->array); + //$field_count = sizeof($this->fields); + $i = 0; + foreach ($this->array as $row) { + $sql .= "("; + $f = 0; + foreach ($this->fields as $field) { + if (isset($row[$field])) { + $sql .= "'".$row[$field]."'"; + } + else { + $sql .= "null"; + } + if ($field_count != $i) { + $sql .= ","; + } + $f++; + } + $sql .= ")"; + if ($row_count != $i) { + $sql .= ",\n"; + } + $i++; + } + $this->db->exec(check_sql($sql)); + unset($sql); + } + + /** + * process method converts the xml cdr and adds it to the database + */ + public function xml_array($row, $leg, $xml_string) { + + //fix the xml by escaping the contents of + if(defined('STDIN')) { + $xml_string = preg_replace_callback("/<([^><]+)>(.*?[><].*?)<\/\g1>/", + function ($matches) { + return '<' . $matches[1] . '>' . + str_replace(">", ">", + str_replace("<", "<", $matches[2]) + ) . + ''; + }, + $xml_string + ); + } + + //parse the xml to get the call detail record info + //try { + // xml_cdr_log($xml_string); + // $xml = simplexml_load_string($xml_string); + // xml_cdr_log("\nxml load done\n"); + //} + //catch(Exception $e) { + // echo $e->getMessage(); + // xml_cdr_log("\nfail loadxml: " . $e->getMessage() . "\n"); + //} + + //misc + $uuid = check_str(urldecode($xml->variables->uuid)); + $this->array[$row]['uuid'] = $uuid; + $this->array[$row]['accountcode'] = check_str(urldecode($xml->variables->accountcode)); + $this->array[$row]['default_language'] = check_str(urldecode($xml->variables->default_language)); + $this->array[$row]['bridge_uuid'] = check_str(urldecode($xml->variables->bridge_uuid)); + //$this->array[$row]['digits_dialed'] = check_str(urldecode($xml->variables->digits_dialed)); + $this->array[$row]['sip_hangup_disposition'] = check_str(urldecode($xml->variables->sip_hangup_disposition)); + $this->array[$row]['pin_number'] = check_str(urldecode($xml->variables->pin_number)); + //time + $this->array[$row]['start_epoch'] = check_str(urldecode($xml->variables->start_epoch)); + $start_stamp = check_str(urldecode($xml->variables->start_stamp)); + $this->array[$row]['start_stamp'] = $start_stamp; + $this->array[$row]['answer_stamp'] = check_str(urldecode($xml->variables->answer_stamp)); + $this->array[$row]['answer_epoch'] = check_str(urldecode($xml->variables->answer_epoch)); + $this->array[$row]['end_epoch'] = check_str(urldecode($xml->variables->end_epoch)); + $this->array[$row]['end_stamp'] = check_str(urldecode($xml->variables->end_stamp)); + $this->array[$row]['duration'] = check_str(urldecode($xml->variables->duration)); + $this->array[$row]['mduration'] = check_str(urldecode($xml->variables->mduration)); + $this->array[$row]['billsec'] = check_str(urldecode($xml->variables->billsec)); + $this->array[$row]['billmsec'] = check_str(urldecode($xml->variables->billmsec)); + //codecs + $this->array[$row]['read_codec'] = check_str(urldecode($xml->variables->read_codec)); + $this->array[$row]['read_rate'] = check_str(urldecode($xml->variables->read_rate)); + $this->array[$row]['write_codec'] = check_str(urldecode($xml->variables->write_codec)); + $this->array[$row]['write_rate'] = check_str(urldecode($xml->variables->write_rate)); + $this->array[$row]['remote_media_ip'] = check_str(urldecode($xml->variables->remote_media_ip)); + $this->array[$row]['hangup_cause'] = check_str(urldecode($xml->variables->hangup_cause)); + $this->array[$row]['hangup_cause_q850'] = check_str(urldecode($xml->variables->hangup_cause_q850)); + //call center + $this->array[$row]['cc_side'] = check_str(urldecode($xml->variables->cc_side)); + $this->array[$row]['cc_member_uuid'] = check_str(urldecode($xml->variables->cc_member_uuid)); + $this->array[$row]['cc_queue_joined_epoch'] = check_str(urldecode($xml->variables->cc_queue_joined_epoch)); + $this->array[$row]['cc_queue'] = check_str(urldecode($xml->variables->cc_queue)); + $this->array[$row]['cc_member_session_uuid'] = check_str(urldecode($xml->variables->cc_member_session_uuid)); + $this->array[$row]['cc_agent'] = check_str(urldecode($xml->variables->cc_agent)); + $this->array[$row]['cc_agent_type'] = check_str(urldecode($xml->variables->cc_agent_type)); + $this->array[$row]['waitsec'] = check_str(urldecode($xml->variables->waitsec)); + //app info + $this->array[$row]['last_app'] = check_str(urldecode($xml->variables->last_app)); + $this->array[$row]['last_arg'] = check_str(urldecode($xml->variables->last_arg)); + //conference + $this->array[$row]['conference_name'] = check_str(urldecode($xml->variables->conference_name)); + $this->array[$row]['conference_uuid'] = check_str(urldecode($xml->variables->conference_uuid)); + $this->array[$row]['conference_member_id'] = check_str(urldecode($xml->variables->conference_member_id)); + //call quality + $rtp_audio_in_mos = check_str(urldecode($xml->variables->rtp_audio_in_mos)); + if (strlen($rtp_audio_in_mos) > 0) { + $this->array[$row]['rtp_audio_in_mos'] = $rtp_audio_in_mos; + } + + //get the values from the callflow. + $x = 0; + foreach ($xml->callflow as $row) { + if ($x == 0) { + $context = check_str(urldecode($row->caller_profile->context)); + $this->array[$row]['destination_number'] = check_str(urldecode($row->caller_profile->destination_number)); + $this->array[$row]['context'] = $context; + $this->array[$row]['network_addr'] = check_str(urldecode($row->caller_profile->network_addr)); + } + $this->array[$row]['caller_id_name'] = check_str(urldecode($row->caller_profile->caller_id_name)); + $this->array[$row]['caller_id_number'] = check_str(urldecode($row->caller_profile->caller_id_number)); + $x++; + } + unset($x); + + //store the call leg + $this->array[$row]['leg'] = $leg; + + //store the call direction + $this->array[$row]['direction'] = check_str(urldecode($xml->variables->call_direction)); + + //store post dial delay, in milliseconds + $this->array[$row]['pdd_ms'] = check_str(urldecode($xml->variables->progress_mediamsec) + urldecode($xml->variables->progressmsec)); + + //get break down the date to year, month and day + $tmp_time = strtotime($start_stamp); + $tmp_year = date("Y", $tmp_time); + $tmp_month = date("M", $tmp_time); + $tmp_day = date("d", $tmp_time); + + //get the domain values from the xml + $domain_name = check_str(urldecode($xml->variables->domain_name)); + $domain_uuid = check_str(urldecode($xml->variables->domain_uuid)); + + //get the domain name from sip_req_host + if (strlen($domain_name) == 0) { + $domain_name = check_str(urldecode($xml->variables->sip_req_host)); + } + + //send the domain name to the cdr log + //xml_cdr_log("\ndomain_name is `$domain_name`; domain_uuid is '$domain_uuid'\n"); + + //get the domain_uuid with the domain_name + if (strlen($domain_uuid) == 0) { + $sql = "select domain_uuid from v_domains "; + if (strlen($domain_name) == 0 && $context != 'public' && $context != 'default') { + $sql .= "where domain_name = '".$context."' "; + } + else { + $sql .= "where domain_name = '".$domain_name."' "; + } + $row = $this->db->query($sql)->fetch(); + $domain_uuid = $row['domain_uuid']; + } + + //set values in the database + if (strlen($domain_uuid) > 0) { + $database->domain_uuid = $domain_uuid; + $this->array[$row]['domain_uuid'] = $domain_uuid; + } + if (strlen($domain_name) > 0) { + $this->array[$row]['domain_name'] = $domain_name; + } + + //check whether a recording exists + $recording_relative_path = '/'.$_SESSION['domain_name'].'/archive/'.$tmp_year.'/'.$tmp_month.'/'.$tmp_day; + if (file_exists($_SESSION['switch']['recordings']['dir'].$recording_relative_path.'/'.$uuid.'.wav')) { + $recording_file = $recording_relative_path.'/'.$uuid.'.wav'; + } + elseif (file_exists($_SESSION['switch']['recordings']['dir'].$recording_relative_path.'/'.$uuid.'.mp3')) { + $recording_file = $recording_relative_path.'/'.$uuid.'.mp3'; + } + if(isset($recording_file) && !empty($recording_file)) { + $this->array[$row]['recording_file'] = $recording_file; + } + + //save to the database in xml format + if ($_SESSION['cdr']['format']['text'] == "xml" && $_SESSION['cdr']['storage']['text'] == "db") { + $this->array[$row]['xml'] = check_str($xml_string); + } + + //save to the database in json format + if ($_SESSION['cdr']['format']['text'] == "json" && $_SESSION['cdr']['storage']['text'] == "db") { + $this->array[$row]['json'] = check_str(json_encode($xml)); + } + + //insert the check_str($extension_uuid) + if (strlen($xml->variables->extension_uuid) > 0) { + $this->array[$row]['extension_uuid'] = check_str(urldecode($xml->variables->extension_uuid)); + } + + //insert xml_cdr into the db + if (strlen($start_stamp) > 0) { + $database->add(); + if ($this->debug) { + echo $database->sql."\n"; + } + } + + //insert the values + if (strlen($uuid) > 0) { + if ($this->debug) { + //$time5_insert = microtime(true); + //echo $sql."
\n"; + } + try { + $error = "false"; + //$this->db->exec(check_sql($sql)); + } + catch(PDOException $e) { + $tmp_dir = $_SESSION['switch']['log']['dir'].'/xml_cdr/failed/'; + if(!file_exists($tmp_dir)) { + mkdir($tmp_dir, 0777, true); + } + if ($_SESSION['cdr']['format']['text'] == "xml") { + $tmp_file = $uuid.'.xml'; + $fh = fopen($tmp_dir.'/'.$tmp_file, 'w'); + fwrite($fh, $xml_string); + } + else { + $tmp_file = $uuid.'.json'; + $fh = fopen($tmp_dir.'/'.$tmp_file, 'w'); + fwrite($fh, json_encode($xml)); + } + fclose($fh); + if ($this->debug) { + echo $e->getMessage(); + } + $error = "true"; + } + + if ($_SESSION['cdr']['storage']['text'] == "dir" && $error != "true") { + if (strlen($uuid) > 0) { + $tmp_time = strtotime($start_stamp); + $tmp_year = date("Y", $tmp_time); + $tmp_month = date("M", $tmp_time); + $tmp_day = date("d", $tmp_time); + $tmp_dir = $_SESSION['switch']['log']['dir'].'/xml_cdr/archive/'.$tmp_year.'/'.$tmp_month.'/'.$tmp_day; + if(!file_exists($tmp_dir)) { + mkdir($tmp_dir, 0777, true); + } + if ($_SESSION['cdr']['format']['text'] == "xml") { + $tmp_file = $uuid.'.xml'; + $fh = fopen($tmp_dir.'/'.$tmp_file, 'w'); + fwrite($fh, $xml_string); + } + else { + $tmp_file = $uuid.'.json'; + $fh = fopen($tmp_dir.'/'.$tmp_file, 'w'); + fwrite($fh, json_encode($xml)); + } + fclose($fh); + } + } + unset($error); + + //if ($this->debug) { + //GLOBAL $insert_time,$insert_count; + //$insert_time+=microtime(true)-$time5_insert; //add this current query. + //$insert_count++; + //} + } + unset($sql); + } + + /** + * get xml from the filesystem and save it to the database + */ + public function read_files() { + $xml_cdr_dir = $_SESSION['switch']['log']['dir'].'/xml_cdr'; + $dir_handle = opendir($xml_cdr_dir); + $x = 0; + $cdr = new $xml_cdr; + while($file = readdir($dir_handle)) { + if ($file != '.' && $file != '..') { + if ( !is_dir($xml_cdr_dir . '/' . $file) ) { + //get the leg of the call and the file prefix + if (substr($file, 0, 2) == "a_") { + $leg = "a"; + $file_prefix = substr($file, 2, 1); + } + else { + $leg = "b"; + $file_prefix = substr($file, 0, 1); + } + + //get the xml cdr string + $xml_string = file_get_contents($xml_cdr_dir.'/'.$file); + + //parse the xml and insert the data into the db + $cdr->xml_array($x, $leg, $xml_string); + + //delete the file after it has been imported + unlink($xml_cdr_dir.'/'.$file); + + //increment + $x++; + } + } + } + $cdr->save(); + closedir($dir_handle); + } + //$this->read_files(); + + /** + * read the call detail records from the http post + */ + public function post() { + if (isset($_POST["cdr"])) { + //debug method + if ($this->debug){ + print_r ($_POST["cdr"]); + } + + //authentication for xml cdr http post + if (!defined('STDIN')) { + if ($_SESSION["cdr"]["http_enabled"]["boolean"] == "true" && strlen($_SESSION["xml_cdr"]["username"]) == 0) { + //get the contents of xml_cdr.conf.xml + $conf_xml_string = file_get_contents($_SESSION['switch']['conf']['dir'].'/autoload_configs/xml_cdr.conf.xml'); + + //parse the xml to get the call detail record info + try { + $conf_xml = simplexml_load_string($conf_xml_string); + } + catch(Exception $e) { + echo $e->getMessage(); + } + foreach ($conf_xml->settings->param as $row) { + if ($row->attributes()->name == "cred") { + $auth_array = explode(":", $row->attributes()->value); + //echo "username: ".$auth_array[0]."
\n"; + //echo "password: ".$auth_array[1]."
\n"; + } + if ($row->attributes()->name == "url") { + //check name is equal to url + } + } + } + } + + //if http enabled is set to false then deny access + if (!defined('STDIN')) { + if ($_SESSION["cdr"]["http_enabled"]["boolean"] == "false") { + echo "access denied
\n"; + return; + } + } + + //check for the correct username and password + if (!defined('STDIN')) { + if ($_SESSION["cdr"]["http_enabled"]["boolean"] == "true") { + if ($auth_array[0] == $_SERVER["PHP_AUTH_USER"] && $auth_array[1] == $_SERVER["PHP_AUTH_PW"]) { + //echo "access granted
\n"; + $_SESSION["xml_cdr"]["username"] = $auth_array[0]; + $_SESSION["xml_cdr"]["password"] = $auth_array[1]; + } + else { + echo "access denied
\n"; + return; + } + } + } + + //loop through all attribues + //foreach($xml->settings->param[1]->attributes() as $a => $b) { + // echo $a,'="',$b,"\"
\n"; + //} + + //get the http post variable + $xml_string = trim($_POST["cdr"]); + + //get the leg of the call + if (substr($_REQUEST['uuid'], 0, 2) == "a_") { + $leg = "a"; + } + else { + $leg = "b"; + } + + //log the xml cdr + //xml_cdr_log("process cdr via post\n"); + + //parse the xml and insert the data into the database + $cdr = new $xml_cdr; + $cdr->xml_array(0, $leg, $xml_string); + $cdr->save(); + } + } + //$this->post(); + + } //end scripts class +} +/* +//example use + $cdr = new xml_cdr; + $csv -> $cdr->extension_summary('csv'); +*/ +?> \ No newline at end of file