2) { chatStatusError('Invalid Cache Engine Configuration.', 500); } //Get businessHoursId and chatEntryId variables $_GET_lower = array_change_key_case($_GET, CASE_LOWER); if (isset($_GET_lower['businesshoursid'])) { $myBusinessHoursId = htmlspecialchars($_GET_lower['businesshoursid']); if (!is_numeric($myBusinessHoursId)) { chatStatusError('businessHoursId not an integer.', 406); } if ( $myBusinessHoursId < $minBusinessHoursId || $myBusinessHoursId > $maxBusinessHoursId ) { chatStatusError('businessHoursId not in allowed range.', 406); } } else { chatStatusError('businessHoursId not set.', 406); } if (isset($_GET_lower['chatentryid'])) { $myChatEntryId = htmlspecialchars($_GET_lower['chatentryid']); if (!is_numeric($myChatEntryId)) { chatStatusError('chatEntryID not an integer', 406); } if ($myChatEntryId < $minChatEntryId || $myChatEntryId > $maxChatEntryId) { chatStatusError('chatEntryId not in allowed range.', 406); } } else { chatStatusError('chatEntryId not set.', 406); } // CCE & ECE URLs $cceBusinessHoursUrl = 'https://' . $ccehostname . '/unifiedconfig/config/businesshour/' . $myBusinessHoursId; //Used for testing when actually API Web Servers are unavailable - use a static XML file - //copy file to local webserver and change cce hostname to be localhost //$cceBusinessHoursUrl = 'http://' . $ccehostname . '/unifiedconfig/config/businesshour/5000.xml'; $eceCapacityUrl = 'https://' . $ecehostname . '/system/egain/chat/entrypoint/capacity/' . $myChatEntryId; $eceLiveSessionUrl = 'https://' . $ecehostname . '/system/egain/chat/entrypoint/liveSessionStatus/' . $myChatEntryId; //Used for testing when ECE API Web Servers are unavailable - use a static XML file. //$eceCapacityUrl = 'http://' . $ecehostname . '/system/egain/chat/entrypoint/capacity/1002.xml'; //$eceLiveSessionUrl = 'http://' . $ecehostname . '/system/egain/chat/entrypoint/liveSessionStatus/1002.xml'; // Memcache Variables (these are the 3 strings stored in the cache engine). $cceBusinessHoursCacheVar = 'chatStatus_cceBusinessHoursId_' . $myBusinessHoursId; $eceCapacityCacheVar = 'chatStatus_eceCapacity_ChatEntryId_' . $myChatEntryId; $eceLiveSessionCacheVar = 'chatStatus_eceLiveSession_ChatEntryId_' . $myChatEntryId; // Connect to Memcached Server if ($cache_engine == 1) { if (!class_exists('Memcache')) { chatStatusError('Memcache Module not installed.', 500); } $memcache = new Memcache(); // @ symbol supresses output errors $memcache_status = @$memcache->connect($cacheEngine_host, 11211); if (!$memcache_status) { chatStatusError('Memcache Connection Error.', 500); } $cceBusinessHoursJSON = $memcache->get($cceBusinessHoursCacheVar); $eceCapacityJSON = $memcache->get($eceCapacityCacheVar); $eceLiveSessionJSON = $memcache->get($eceLiveSessionCacheVar); } // Connect to Redis Server if ($cache_engine == 2) { if (!class_exists('Redis')) { chatStatusError('Redis Module not installed.', 500); } $redis = new Redis(); try { $redis->connect($cacheEngine_host, 6379, 3); } catch (Exception $e) { chatStatusError('Redis Connection Error.', 500); } $cceBusinessHoursJSON = $redis->get($cceBusinessHoursCacheVar); $eceCapacityJSON = $redis->get($eceCapacityCacheVar); $eceLiveSessionJSON = $redis->get($eceLiveSessionCacheVar); } //Check if cceBusinessHours Data is in Cache if ($cceBusinessHoursJSON != null) { // Cache available $cceBusinessHoursObj = json_decode($cceBusinessHoursJSON); $cceBusinessHoursObj->cache = true; $cceBusinessHoursJSON = json_encode($cceBusinessHoursObj); $cceBusinessHoursAPI = 'From Cache'; } else { // Cache miss $cceBusinessHoursObj = cceBusinessHoursAPI($cceBusinessHoursUrl); $cceBusinessHoursJSON = json_encode($cceBusinessHoursObj); $cceBusinessHoursObj->cache = false; $cceBusinessHoursAPI = 'From Source'; if ($cache_engine == 1) { $memcache->set( $cceBusinessHoursCacheVar, $cceBusinessHoursJSON, 0, $cache_ttl ); } if ($cache_engine == 2) { $redis->setex( $cceBusinessHoursCacheVar, $cache_ttl, $cceBusinessHoursJSON ); } } $chatStatus = $cceBusinessHoursObj->Status; $chatStatusReason = $cceBusinessHoursObj->runTimeStatusReason; $chatTimer = $cceBusinessHoursObj->ChatTimer; if ($cceBusinessHoursObj->Status !== 'open') { $chatStatus = 'closed'; $chatStatusReason = $cceBusinessHoursObj->runTimeStatusReason; $errorcode = $cceBusinessHoursObj->errorcode; $errorstring = $cceBusinessHoursObj->errorstring; chatStatusResponse(); } // Check eceCapacityAPI // Only check this ECE Capacity API if the min Agent Count is specificed as non zero. if ($cceBusinessHoursObj->MinAgentCount > 0) { if ($eceCapacityJSON != null) { // Cache hit // Render from cache $eceCapacityObj = json_decode($eceCapacityJSON); $eceCapacityObj->cache = true; $eceCapacityAPI = 'From Cache'; $eceCapacityJSON = json_encode($eceCapacityObj); } else { // Cache miss $eceCapacityObj = eceCapacityAPI( $eceCapacityUrl, $cceBusinessHoursObj->MinAgentCount ); $eceCapacityObj->cache = false; $eceCapacityAPI = 'From Source'; $eceCapacityJSON = json_encode($eceCapacityObj); if ($cache_engine == 1) { $memcache->set( $eceCapacityCacheVar, $eceCapacityJSON, 0, $cache_ttl ); } if ($cache_engine == 2) { $redis->setex($eceCapacityCacheVar, $cache_ttl, $eceCapacityJSON); } } if ($eceCapacityObj->Status !== 'open') { $chatStatus = $eceCapacityObj->Status; $chatStatusReason = $eceCapacityObj->BusyReason; $errorcode = $eceCapacityObj->errorcode; $errorstring = $eceCapacityObj->errorstring; chatStatusResponse(); } } // Check eceLiveSessionAPI // Only Check the ECE Live Session API if $cceBusinessHoursObj->MaxQueueDepth and $cceBusinessHoursObj->MaxWaitTime are both are NOT the integer '0'. if ( $cceBusinessHoursObj->MaxQueueDepth !== 0 || $cceBusinessHoursObj->MaxWaitTime !== 0 ) { if ($eceLiveSessionJSON != null) { // Cache hit // Render from cache $eceLiveSessionObj = json_decode($eceLiveSessionJSON); $eceLiveSessionObj->cache = true; $eceLiveSessionAPI = 'From Cache'; $eceLiveSessionJSON = json_encode($eceLiveSessionObj); } else { // Cache miss $eceLiveSessionObj = eceLiveSessionAPI( $eceLiveSessionUrl, $cceBusinessHoursObj->MaxQueueDepth, $cceBusinessHoursObj->MaxWaitTime ); $eceLiveSessionObj->cache = false; $eceLiveSessionAPI = 'From Source'; $eceLiveSessionJSON = json_encode($eceLiveSessionObj); if ($cache_engine == 1) { $memcache->set( $eceLiveSessionCacheVar, $eceLiveSessionJSON, 0, $cache_ttl ); } if ($cache_engine == 2) { $redis->setex( $eceLiveSessionCacheVar, $cache_ttl, $eceLiveSessionJSON ); } } $chatStatus = $eceLiveSessionObj->Status; $chatStatusReason = $eceLiveSessionObj->BusyReason; $errorcode = $eceLiveSessionObj->errorcode; $errorstring = $eceLiveSessionObj->errorstring; } chatStatusResponse(); /*chatStatusError*/ //This function should only be called if Memcached / Redis is down or invalid url parameters. function chatStatusError($errormessage, $code) { global $debuglevel; $chatStatus = 'closed'; $chatStatusReason = 'out of service'; $chatTimer = 0; $errorcode = $code; http_response_code($code); //SET HTTP Error Response Code $errorstring = $errormessage; $chatStatusObj = new \stdClass(); $chatStatusObj->chatstatus = $chatStatus; $chatStatusObj->chatStatusReason = $chatStatusReason; $chatStatusObj->chatTimer = $chatTimer; $chatStatusObj->errorcode = $errorcode; $chatStatusObj->errorstring = $errorstring; $chatStatusObj->debuglevel = $debuglevel; $chatStatusJSON = json_encode($chatStatusObj); echo $chatStatusJSON; exit(); } function chatStatusResponse() { global $debuglevel, $chatStatus, $chatStatusReason, $chatTimer, $errorcode, $errorstring, $cache_engine; global $cceBusinessHoursAPI, $eceCapacityAPI, $eceLiveSessionAPI, $cceBusinessHoursObj, $eceCapacityObj, $eceLiveSessionObj; $chatStatusObj = new \stdClass(); $chatStatusObj->chatStatus = $chatStatus; $chatStatusObj->chatStatusReason = $chatStatusReason; if ($chatStatus !== 'open') { $chatStatusObj->chatTimer = 0; } else { $chatStatusObj->chatTimer = $chatTimer; } $chatStatusObj->errorCode = $errorcode; if ($errorcode >= 400 or $errorcode < 600) { //http_response_code($errorcode); //Not setting HTTP as an error - defaults to 200 OK - use errorCode in Body to determine an errror } $chatStatusObj->errorString = $errorstring; $chatStatusObj->debugLevel = $debuglevel; if ($cache_engine == 0) { $chatStatusObj->cacheEngine = 'Disabled'; } if ($cache_engine == 1) { $chatStatusObj->cacheEngine = 'Memcached'; } if ($cache_engine == 2) { $chatStatusObj->cacheEngine = 'Redis'; } if ($debuglevel > 1) { $chatStatusObj->cceBusinessHoursAPI = $cceBusinessHoursAPI; $chatStatusObj->eceCapacityAPI = $eceCapacityAPI; $chatStatusObj->eceLiveSessionAPI = $eceLiveSessionAPI; } if ($debuglevel > 2) { $chatStatusObj->cceBusinessHoursObj = $cceBusinessHoursObj; $chatStatusObj->eceCapacityObj = $eceCapacityObj; $chatStatusObj->eceLiveSessionObj = $eceLiveSessionObj; } $chatStatusJSON = json_encode($chatStatusObj); echo $chatStatusJSON; exit(); } function cceBusinessHoursAPI($url) { global $cceuser, $ccepass, $tls_cert_check, $http_connect_timeout, $http_timeout; global $defaultProactiveChatTimer, $defaultMinAgentCount, $defaultMaxQueueDepth, $defaultMaxWaitTime, $debuglevel; $cceBusinessHoursObj = new \stdClass(); // Initial Values $cceBusinessHoursObj->API = 'cceBusinessHours'; $cceBusinessHoursObj->Name = 'Unknown'; $cceBusinessHoursObj->Status = 'closed'; $cceBusinessHoursObj->runTimeStatusReason = 'out of service'; $cceBusinessHoursObj->ChatTimer = $defaultProactiveChatTimer; $cceBusinessHoursObj->MinAgentCount = $defaultMinAgentCount; $cceBusinessHoursObj->MaxQueueDepth = $defaultMaxQueueDepth; $cceBusinessHoursObj->MaxWaitTime = $defaultMaxWaitTime; $cceBusinessHoursObj->errorcode = 0; $cceBusinessHoursObj->errorstring = ''; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $tls_cert_check); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $tls_cert_check); curl_setopt($ch, CURLOPT_USERPWD, "$cceuser:$ccepass"); curl_setopt($ch, CURLOPT_HTTPGET, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $http_connect_timeout); //connection timeout curl_setopt($ch, CURLOPT_TIMEOUT, $http_timeout); //timeout in seconds for request curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); //CURL to use IPV4 DNS lookup only (and not attempt both DNS for IPV4 and IPV6 records) $api_response = curl_exec($ch); //$info = curl_getinfo($ch); //print_r ($info); //exit(); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $cceBusinessHoursObj->httpcode = $httpcode; if ($httpcode !== 200) { $cceBusinessHoursObj->errorstring = 'CCE BusinessHours HTTP Error.'; //Error Log error_log("CCE BusinessHours HTTP ERROR. HTTPURL: $url HTTPCode: $httpcode",0); error_log('Curl ErrorCode: ' . curl_errno($ch)); error_log('Curl ErrorString: ' . curl_error($ch)); if ($debuglevel > 2) { $info = curl_getinfo($ch); error_log(json_encode($info, JSON_UNESCAPED_SLASHES), 0); } if ($httpcode !== 0) { $cceBusinessHoursObj->errorcode = $httpcode; //http_response_code($httpcode); } else { $cceBusinessHoursObj->errorcode = 504; //http_response_code(500); } curl_close($ch); return $cceBusinessHoursObj; } curl_close($ch); //Supress Warnings if response cannot be parsed. $xml = @simplexml_load_string($api_response); if ($xml) { //continue } else { $cceBusinessHoursObj->errorcode = 500; $cceBusinessHoursObj->errorstring = 'Error parsing XML'; return $cceBusinessHoursObj; } //print_r($xml); if (isset($xml->name)) { $bh_name = (string) $xml->name; } else { $cceBusinessHoursObj->errorcode = 500; $cceBusinessHoursObj->errorstring = 'Unable to retrieve Business Hour Name'; return $cceBusinessHoursObj; } $cceBusinessHoursObj->Name = $bh_name; if (isset($xml->runTimeStatus)) { $bh_status = (int) $xml->runTimeStatus; } else { $cceBusinessHoursObj->errorcode = 500; $cceBusinessHoursObj->errorstring = 'Unable to retrieve runTimeStatus'; return $cceBusinessHoursObj; } $cceBusinessHoursObj->runTimeStatus = $bh_status; if (isset($xml->runTimeStatusReason)) { $bh_statusReason = (string) $xml->runTimeStatusReason; } else { $cceBusinessHoursObj->errorcode = 500; $cceBusinessHoursObj->errorstring = 'Unable to retrieve runTimeStatusReason'; return $cceBusinessHoursObj; } $cceBusinessHoursObj->runTimeStatusReason = $bh_statusReason; //Parse the Business name using underscore to find the configured Chat Values $myvar = explode('_', $bh_name); if (isset($myvar[1]) && is_numeric($myvar[1])) { $myProactiveChatTimer = $myvar[1]; } else { $myProactiveChatTimer = $defaultProactiveChatTimer; } if (isset($myvar[2]) && is_numeric($myvar[2])) { $myMinAgentCount = $myvar[2]; } else { $myMinAgentCount = $defaultMinAgentCount; } if (isset($myvar[3]) && is_numeric($myvar[3])) { $myMaxQueueDepth = $myvar[3]; } else { $myMaxQueueDepth = $defaultMaxQueueDepth; } if (isset($myvar[4]) && is_numeric($myvar[4])) { $myMaxWaitTime = $myvar[4]; } else { $myMaxWaitTime = $defaultMaxWaitTime; } $myProactiveChatTimer = $myProactiveChatTimer * 1000; //convert to ms if ($bh_status == 1 or $bh_status == 3) { $chatStatus = 'open'; } else { $chatStatus = 'closed'; } $cceBusinessHoursObj->Status = $chatStatus; // Note by converting to an integer if they variable value is invalid, the value will return zero - which is good - as its the disables the check. $cceBusinessHoursObj->ChatTimer = intval($myProactiveChatTimer); $cceBusinessHoursObj->MinAgentCount = intval($myMinAgentCount); $cceBusinessHoursObj->MaxQueueDepth = intval($myMaxQueueDepth); $cceBusinessHoursObj->MaxWaitTime = intval($myMaxWaitTime); $cceBusinessHoursObj->errorstring = ''; return $cceBusinessHoursObj; } // ECE Capacity API - Checking Agents availability function eceCapacityAPI($url, $MinAgentCount) { global $tls_cert_check, $http_connect_timeout, $http_timeout, $debuglevel; $eceCapacityObj = new \stdClass(); // Initial Values $eceCapacityObj->API = 'eceCapacity'; $eceCapacityObj->Status = 'closed'; $eceCapacityObj->BusyReason = 'out of service'; $eceCapacityObj->MinAgentCount = $MinAgentCount; $eceCapacityObj->errorcode = 0; $eceCapacityObj->errorstring = ''; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $tls_cert_check); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $tls_cert_check); curl_setopt($ch, CURLOPT_HTTPGET, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $http_connect_timeout); //connection timeout curl_setopt($ch, CURLOPT_TIMEOUT, $http_timeout); //timeout in seconds for request curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); //CURL to use IPV4 DNS lookup only (and not attempt both DNS for IPV4 and IPV6 records) $api_response = curl_exec($ch); //$info = curl_getinfo($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $eceCapacityObj->httpcode = $httpcode; if ($httpcode !== 200) { $eceCapacityObj->errorstring = 'ECE Capacity HTTP Error.'; //Error Log error_log( "ECE Capacity HTTP Error. HTTPURL: $url HTTPCode: $httpcode", 0 ); error_log('Curl ErrorCode: ' . curl_errno($ch)); error_log('Curl ErrorString: ' . curl_error($ch)); if ($debuglevel > 2) { $info = curl_getinfo($ch); error_log(json_encode($info, JSON_UNESCAPED_SLASHES), 0); } if ($httpcode !== 0) { $eceCapacityObj->errorcode = $httpcode; } else { $eceCapacityObj->errorcode = 504; } curl_close($ch); return $eceCapacityObj; } curl_close($ch); $xml_data = str_replace('ns2:', '', $api_response); //Suppress errors if unable to parse XML using @ $xml_capacity = @simplexml_load_string($xml_data); //Confirming we were able to parse the XML if ($xml_capacity) { //continue } else { $eceCapacityObj->errorstring = 'Erroring parsing XML'; return $eceCapacityObj; } // Check if 'count' is in XML and also if its numerical. Note - don't convert to interger before check as any string value would return 0 if converted to interger - which would pass numeric test. if ( isset($xml_capacity->count) && is_numeric((string) $xml_capacity->count) ) { $agentcount = (int) $xml_capacity->count; } else { $eceCapacityObj->errorstring = 'Invalid MinAgentCount'; return $eceCapacityObj; } $eceCapacityObj->AgentCount = $agentcount; if ($agentcount >= $MinAgentCount) { $eceCapacityObj->Status = 'open'; $eceCapacityObj->BusyReason = ''; } else { $eceCapacityObj->Status = 'busy'; $eceCapacityObj->BusyReason = 'MinAgentCount'; } return $eceCapacityObj; } function eceLiveSessionAPI($url, $MaxQueueDepth, $MaxWaitTime) { global $tls_cert_check, $http_connect_timeout, $http_timeout, $debuglevel; $eceLiveSessionObj = new \stdClass(); // Initial Values $eceLiveSessionObj->API = 'eceLiveSession'; $eceLiveSessionObj->Status = 'closed'; $eceLiveSessionObj->BusyReason = 'out of service'; $eceLiveSessionObj->errorcode = 0; $eceLiveSessionObj->errorstring = ''; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $tls_cert_check); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $tls_cert_check); curl_setopt($ch, CURLOPT_HTTPGET, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $http_connect_timeout); //connection timeout curl_setopt($ch, CURLOPT_TIMEOUT, $http_timeout); //timeout in seconds for request curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); //CURL to use IPV4 DNS lookup only (and not attempt both DNS for IPV4 and IPV6 records) $api_response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); //$info = curl_getinfo($ch); $eceLiveSessionObj->httpcode = $httpcode; if ($httpcode !== 200) { $eceLiveSessionObj->errorstring = 'ECE LiveSession HTTP Error.'; //Error Log error_log( "ECE LiveSession HTTP Error. HTTPURL: $url HTTPCode: $httpcode", 0 ); error_log('Curl ErrorCode: ' . curl_errno($ch)); error_log('Curl ErrorString: ' . curl_error($ch)); if ($debuglevel > 2) { $info = curl_getinfo($ch); error_log(json_encode($info, JSON_UNESCAPED_SLASHES), 0); } if ($httpcode !== 0) { $eceLiveSessionObj->errorcode = $httpcode; } else { $eceLiveSessionObj->errorcode = 504; } curl_close($ch); return $eceLiveSessionObj; } curl_close($ch); $xml_data = str_replace('ns2:', '', $api_response); //Supress Errors if unable to parse XML $xml_liveSessionStatus = @simplexml_load_string($xml_data); if ($xml_liveSessionStatus) { //continue } else { $eceLiveSessionObj->errorstring = 'Error parsing XML'; return $eceLiveSessionObj; } if ( isset($xml_liveSessionStatus->queueDepth) && is_numeric((string) $xml_liveSessionStatus->queueDepth) ) { $queueDepth = (int) $xml_liveSessionStatus->queueDepth; } else { $eceLiveSessionObj->errorstring = 'Unable to read queueDepth'; return $eceLiveSessionObj; } if ( isset($xml_liveSessionStatus->waitTime) && is_numeric((string) $xml_liveSessionStatus->waitTime) ) { $waitTime = (int) $xml_liveSessionStatus->waitTime; } else { $eceLiveSessionObj->errorstring = 'Unable to read waitTime'; return $eceLiveSessionObj; } $eceLiveSessionObj->MaxQueueDepth = $MaxQueueDepth; $eceLiveSessionObj->MaxWaitTime = $MaxWaitTime; $eceLiveSessionObj->queueDepth = $queueDepth; $eceLiveSessionObj->waitTime = $waitTime; // Go Busy if Queue Depth is greater than Max Queue Depth - unless Max Queue Depth is set to 0 (i.e. Max Queue Depth if 0 disables the check). if ($MaxQueueDepth != 0 && $queueDepth > $MaxQueueDepth) { $eceLiveSessionObj->Status = 'busy'; $eceLiveSessionObj->BusyReason = 'MaxQueueDepth'; $eceLiveSessionObj->errorstring = ''; } else { if ($MaxWaitTime != 0 && $waitTime > $MaxWaitTime && $queueDepth != 0) { $eceLiveSessionObj->Status = 'busy'; $eceLiveSessionObj->BusyReason = 'MaxWaitTime'; $eceLiveSessionObj->errorstring = ''; } else { $eceLiveSessionObj->Status = 'open'; $eceLiveSessionObj->BusyReason = ''; $eceLiveSessionObj->errorstring = ''; } } return $eceLiveSessionObj; } ?>