* @copyright (C) 2006 - 2012 Adam Armstrong (as Observium)
* @copyright (C) 2013 LibreNMS Group
*/
use LibreNMS\Config;
/**
* Compare $t with the value of $vars[$v], if that exists
* @param string $v Name of the var to test
* @param string $t Value to compare $vars[$v] to
* @return boolean true, if values are the same, false if $vars[$v] is unset or values differ
*/
function var_eq($v, $t)
{
global $vars;
if (isset($vars[$v]) && $vars[$v] == $t) {
return true;
}
return false;
}
/**
* Get the value of $vars[$v], if it exists
* @param string $v Name of the var to get
* @return string|boolean The value of $vars[$v] if it exists, false if it does not exist
*/
function var_get($v)
{
global $vars;
if (isset($vars[$v])) {
return $vars[$v];
}
return false;
}
function data_uri($file, $mime)
{
$contents = file_get_contents($file);
$base64 = base64_encode($contents);
return ('data:' . $mime . ';base64,' . $base64);
}//end data_uri()
/**
* Convert string to nice case, mostly used for applications
*
* @param $item
* @return mixed|string
*/
function nicecase($item)
{
return \LibreNMS\Util\StringHelpers::niceCase($item);
}
function toner2colour($descr, $percent)
{
$colour = get_percentage_colours(100 - $percent);
if (substr($descr, -1) == 'C' || stripos($descr, 'cyan') !== false) {
$colour['left'] = '55D6D3';
$colour['right'] = '33B4B1';
}
if (substr($descr, -1) == 'M' || stripos($descr, 'magenta') !== false) {
$colour['left'] = 'F24AC8';
$colour['right'] = 'D028A6';
}
if (substr($descr, -1) == 'Y' || stripos($descr, 'yellow') !== false
|| stripos($descr, 'giallo') !== false
|| stripos($descr, 'gul') !== false
) {
$colour['left'] = 'FFF200';
$colour['right'] = 'DDD000';
}
if (substr($descr, -1) == 'K' || stripos($descr, 'black') !== false
|| stripos($descr, 'nero') !== false
) {
$colour['left'] = '000000';
$colour['right'] = '222222';
}
return $colour;
}//end toner2colour()
/**
* Find all links in some text and turn them into html links.
*
* @param string $text
* @return string
*/
function linkify($text)
{
$regex = "#(http|https|ftp|ftps)://[a-z0-9\-.]*[a-z0-9\-]+(/\S*)?#i";
return preg_replace($regex, '$0', $text);
}
function generate_link($text, $vars, $new_vars = array())
{
return '' . $text . '';
}//end generate_link()
function generate_url($vars, $new_vars = [])
{
return \LibreNMS\Util\Url::generate($vars, $new_vars);
}
function escape_quotes($text)
{
return str_replace('"', "\'", str_replace("'", "\'", $text));
}//end escape_quotes()
function generate_overlib_content($graph_array, $text)
{
$overlib_content = '
';
return ($return);
}//end generate_pagination()
function demo_account()
{
print_error("You are logged in as a demo account, this page isn't accessible to you");
}//end demo_account()
function get_client_ip()
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$client_ip = $_SERVER['REMOTE_ADDR'];
}
return $client_ip;
}//end get_client_ip()
/**
* @param $string
* @param int $max
* @return string
*/
function shorten_text($string, $max = 30)
{
return \LibreNMS\Util\StringHelpers::shortenText($string, $max);
}
function shorten_interface_type($string)
{
return str_ireplace(
array(
'FastEthernet',
'TenGigabitEthernet',
'GigabitEthernet',
'Port-Channel',
'Ethernet',
'Bundle-Ether',
),
array(
'Fa',
'Te',
'Gi',
'Po',
'Eth',
'BE',
),
$string
);
}//end shorten_interface_type()
function clean_bootgrid($string)
{
$output = str_replace(array("\r", "\n"), '', $string);
$output = addslashes($output);
return $output;
}//end clean_bootgrid()
function get_url()
{
// http://stackoverflow.com/questions/2820723/how-to-get-base-url-with-php
// http://stackoverflow.com/users/184600/ma%C4%8Dek
return sprintf(
'%s://%s%s',
isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http',
$_SERVER['SERVER_NAME'],
$_SERVER['REQUEST_URI']
);
}//end get_url()
function alert_details($details)
{
if (!is_array($details)) {
$details = json_decode(gzuncompress($details), true);
}
$fault_detail = '';
foreach ($details['rule'] as $o => $tmp_alerts) {
$fallback = true;
$fault_detail .= '#' . ($o + 1) . ': ';
if ($tmp_alerts['bill_id']) {
$fault_detail .= '' . $tmp_alerts['bill_name'] . '; ';
$fallback = false;
}
if ($tmp_alerts['port_id']) {
$tmp_alerts = cleanPort($tmp_alerts);
$fault_detail .= generate_port_link($tmp_alerts) . '; ';
$fallback = false;
}
if ($tmp_alerts['accesspoint_id']) {
$fault_detail .= generate_ap_link($tmp_alerts, $tmp_alerts['name']) . '; ';
$fallback = false;
}
if ($tmp_alerts['sensor_id']) {
$details = "Current Value: " . $tmp_alerts['sensor_current'] . " (" . $tmp_alerts['sensor_class'] . ") ";
$details_a = [];
if ($tmp_alerts['sensor_limit_low']) {
$details_a[] = "low: " . $tmp_alerts['sensor_limit_low'];
}
if ($tmp_alerts['sensor_limit_low_warn']) {
$details_a[]= "low_warn: " . $tmp_alerts['sensor_limit_low_warn'];
}
if ($tmp_alerts['sensor_limit_warn']) {
$details_a[]= "high_warn: " . $tmp_alerts['sensor_limit_warn'];
}
if ($tmp_alerts['sensor_limit']) {
$details_a[]= "high: " . $tmp_alerts['sensor_limit'];
}
$details .= implode(', ', $details_a);
$fault_detail .= generate_sensor_link($tmp_alerts, $tmp_alerts['name']) . '; ' . $details;
$fallback = false;
}
if ($tmp_alerts['bgpPeer_id']) {
// If we have a bgpPeer_id, we format the data accordingly
$fault_detail .= "BGP peer 'device',
'device' => $tmp_alerts['device_id'],
'tab' => 'routing',
'proto' => 'bgp')) .
"'>" . $tmp_alerts['bgpPeerIdentifier'] . "";
$fault_detail .= ", AS" . $tmp_alerts['bgpPeerRemoteAs'];
$fault_detail .= ", State " . $tmp_alerts['bgpPeerState'];
$fallback = false;
}
if ($tmp_alerts['type'] && $tmp_alerts['label']) {
if ($tmp_alerts['error'] == "") {
$fault_detail .= ' ' . $tmp_alerts['type'] . ' - ' . $tmp_alerts['label'] . '; ';
} else {
$fault_detail .= ' ' . $tmp_alerts['type'] . ' - ' . $tmp_alerts['label'] . ' - ' . $tmp_alerts['error'] . '; ';
}
$fallback = false;
}
if ($fallback === true) {
foreach ($tmp_alerts as $k => $v) {
if (!empty($v) && $k != 'device_id' && (stristr($k, 'id') || stristr($k, 'desc') || stristr($k, 'msg')) && substr_count($k, '_') <= 1) {
$fault_detail .= "$k => '$v', ";
}
}
$fault_detail = rtrim($fault_detail, ', ');
}
$fault_detail .= ' ';
}//end foreach
return $fault_detail;
}//end alert_details()
function dynamic_override_config($type, $name, $device)
{
$attrib_val = get_dev_attrib($device, $name);
if ($attrib_val == 'true') {
$checked = 'checked';
} else {
$checked = '';
}
if ($type == 'checkbox') {
return '';
} elseif ($type == 'text') {
return '';
}
}//end dynamic_override_config()
/**
* Return the rows from 'ports' for all ports of a certain type as parsed by port_descr_parser.
* One or an array of strings can be provided as an argument; if an array is passed, all ports matching
* any of the types in the array are returned.
* @param $types mixed String or strings matching 'port_descr_type's.
* @return array Rows from the ports table for matching ports.
*/
function get_ports_from_type($given_types)
{
# Make the arg an array if it isn't, so subsequent steps only have to handle arrays.
if (!is_array($given_types)) {
$given_types = array($given_types);
}
# Check the config for a '_descr' entry for each argument. This is how a 'custom_descr' entry can
# be key/valued to some other string that's actually searched for in the DB. Merge or append the
# configured value if it's an array or a string. Or append the argument itself if there's no matching
# entry in config.
$search_types = [];
foreach ($given_types as $type) {
if (Config::has($type . '_descr')) {
$type_descr = Config::get($type . '_descr');
if (is_array($type_descr)) {
$search_types = array_merge($search_types, $type_descr);
} else {
$search_types[] = $type_descr;
}
} else {
$search_types[] = $type;
}
}
# Using the full list of strings to search the DB for, build the 'where' portion of a query that
# compares 'port_descr_type' with entry in the list. Also, since '@' is the convential wildcard,
# replace it with '%' so it functions as a wildcard in the SQL query.
$type_where = ' (';
$or = '';
$type_param = array();
foreach ($search_types as $type) {
if (!empty($type)) {
$type = strtr($type, '@', '%');
$type_where .= " $or `port_descr_type` LIKE ?";
$or = 'OR';
$type_param[] = $type;
}
}
$type_where .= ') ';
# Run the query with the generated 'where' and necessary parameters, and send it back.
$ports = dbFetchRows("SELECT * FROM `ports` as I, `devices` AS D WHERE $type_where AND I.device_id = D.device_id ORDER BY I.ifAlias", $type_param);
return $ports;
}
/**
* @param $filename
* @param $content
*/
function file_download($filename, $content)
{
$length = strlen($content);
header('Content-Description: File Transfer');
header('Content-Type: text/plain');
header("Content-Disposition: attachment; filename=$filename");
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . $length);
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
header('Pragma: public');
echo $content;
}
function get_rules_from_json()
{
return json_decode(file_get_contents(Config::get('install_dir') . '/misc/alert_rules.json'), true);
}
function search_oxidized_config($search_in_conf_textbox)
{
$oxidized_search_url = Config::get('oxidized.url') . '/nodes/conf_search?format=json';
$postdata = http_build_query(
array(
'search_in_conf_textbox' => $search_in_conf_textbox,
)
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
$nodes = json_decode(file_get_contents($oxidized_search_url, false, $context), true);
// Look up Oxidized node names to LibreNMS devices for a link
foreach ($nodes as &$n) {
$dev = device_by_name($n['node']);
$n['dev_id'] = $dev ? $dev['device_id'] : false;
}
return $nodes;
}
/**
* @param $data
* @return bool|mixed
*/
function array_to_htmljson($data)
{
if (is_array($data)) {
$data = htmlentities(json_encode($data));
return str_replace(',', ', ', $data);
} else {
return false;
}
}
/**
* @param int $eventlog_severity
* @return string $eventlog_severity_icon
*/
function eventlog_severity($eventlog_severity)
{
switch ($eventlog_severity) {
case 1:
return "label-success"; //OK
case 2:
return "label-info"; //Informational
case 3:
return "label-primary"; //Notice
case 4:
return "label-warning"; //Warning
case 5:
return "label-danger"; //Critical
default:
return "label-default"; //Unknown
}
} // end eventlog_severity
/**
*
*/
function set_image_type()
{
return header('Content-type: ' . get_image_type());
}
function get_image_type()
{
if (Config::get('webui.graph_type') === 'svg') {
return 'image/svg+xml';
} else {
return 'image/png';
}
}
function get_oxidized_nodes_list()
{
$context = stream_context_create(array(
'http' => array(
'header' => "Accept: application/json",
)
));
$data = json_decode(file_get_contents(Config::get('oxidized.url') . '/nodes?format=json', false, $context), true);
foreach ($data as $object) {
$device = device_by_name($object['name']);
if (! device_permitted($device['device_id'])) {
//user cannot see this device, so let's skip it.
continue;
}
echo "
" . $device['device_id'] . "
" . $object['name'] . "
" . $device['sysName'] . "
" . $object['status'] . "
" . $object['time'] . "
" . $object['model'] . "
" . $object['group'] . "
";
}
}
// fetches disks for a system
function get_disks($device)
{
return dbFetchRows('SELECT * FROM `ucd_diskio` WHERE device_id = ? ORDER BY diskio_descr', array($device));
}
/**
* Get the fail2ban jails for a device... just requires the device ID
* an empty return means either no jails or fail2ban is not in use
* @param $device_id
* @return array
*/
function get_fail2ban_jails($device_id)
{
$options = array(
'filter' => array(
'type' => array('=', 'fail2ban'),
),
);
$component = new LibreNMS\Component();
$f2bc = $component->getComponents($device_id, $options);
if (isset($f2bc[$device_id])) {
$id = $component->getFirstComponentID($f2bc, $device_id);
return json_decode($f2bc[$device_id][$id]['jails']);
}
return array();
}
/**
* Get the Postgres databases for a device... just requires the device ID
* an empty return means Postres is not in use
* @param $device_id
* @return array
*/
function get_postgres_databases($device_id)
{
$options = array(
'filter' => array(
'type' => array('=', 'postgres'),
),
);
$component = new LibreNMS\Component();
$pgc = $component->getComponents($device_id, $options);
if (isset($pgc[$device_id])) {
$id = $component->getFirstComponentID($pgc, $device_id);
return json_decode($pgc[$device_id][$id]['databases']);
}
return array();
}
/**
* Get all application data from the collected
* rrd files.
*
* @param array $device device for which we get the rrd's
* @param int $app_id application id on the device
* @param string $category which category of seafile graphs are searched
* @return array list of entry data
*/
function get_arrays_with_application($device, $app_id, $app_name, $category = null)
{
$entries = array();
if ($category) {
$pattern = sprintf('%s/%s-%s-%s-%s-*.rrd', get_rrd_dir($device['hostname']), 'app', $app_name, $app_id, $category);
} else {
$pattern = sprintf('%s/%s-%s-%s-*.rrd', get_rrd_dir($device['hostname']), 'app', $app_name, $app_id);
}
foreach (glob($pattern) as $rrd) {
$filename = basename($rrd, '.rrd');
list(,,, $entry) = explode("-", $filename, 4);
if ($entry) {
array_push($entries, $entry);
}
}
return $entries;
}
/**
* Get all certificate names from the collected
* rrd files.
*
* @param array $device device for which we get the rrd's
* @param int $app_id application id on the device
* @return array list of certificate names
*/
function get_domains_with_certificates($device, $app_id)
{
$app_name = 'certificate';
return get_arrays_with_application($device, $app_id, $app_name);
}
/**
* Get all seafile data from the collected
* rrd files.
*
* @param array $device device for which we get the rrd's
* @param int $app_id application id on the device
* @param string $category which category of seafile graphs are searched
* @return array list of seafile data
*/
function get_arrays_with_seafile($device, $app_id, $category)
{
$app_name = 'seafile';
return get_arrays_with_application($device, $app_id, $app_name, $category);
}
/**
* Get all mdadm arrays from the collected
* rrd files.
*
* @param array $device device for which we get the rrd's
* @param int $app_id application id on the device
* @return array list of raid-arrays
*/
function get_arrays_with_mdadm($device, $app_id)
{
$app_name = 'mdadm';
return get_arrays_with_application($device, $app_id, $app_name);
}
/**
* Get all disks (disk serial numbers) from the collected
* rrd files.
*
* @param array $device device for which we get the rrd's
* @param int $app_id application id on the device
* @return array list of disks
*/
function get_disks_with_smart($device, $app_id)
{
$app_name = 'smart';
return get_arrays_with_application($device, $app_id, $app_name);
}
/**
* Gets all dashboards the user can access
* adds in the keys:
* username - the username of the owner of each dashboard
* default - the default dashboard for the logged in user
*
* @param int $user_id optionally get list for another user
* @return array list of dashboards
*/
function get_dashboards($user_id = null)
{
$user = is_null($user_id) ? Auth::user() : \App\Models\User::find($user_id);
$default = get_user_pref('dashboard');
return \App\Models\Dashboard::allAvailable($user)->with('user')->get()->map(function ($dashboard) use ($default) {
$dash = $dashboard->toArray();
$dash['username'] = $dashboard->user ? $dashboard->user->username : '';
$dash['default'] = $default == $dashboard->dashboard_id;
return $dash;
})->keyBy('dashboard_id')->all();
}
/**
* Return stacked graphs information
*
* @param string $transparency value of desired transparency applied to rrdtool options (values 01 - 99)
* @return array containing transparency and stacked setup
*/
function generate_stacked_graphs($transparency = '88')
{
if (Config::get('webui.graph_stacked') == true) {
return array('transparency' => $transparency, 'stacked' => '1');
} else {
return array('transparency' => '', 'stacked' => '-1');
}
}
/**
* Parse AT time spec, does not handle the entire spec.
* @param string $time
* @return int
*/
function parse_at_time($time)
{
if (is_numeric($time)) {
return $time < 0 ? time() + $time : intval($time);
}
if (preg_match('/^[+-]\d+[hdmy]$/', $time)) {
$units = [
'm' => 60,
'h' => 3600,
'd' => 86400,
'y' => 31557600,
];
$value = substr($time, 1, -1);
$unit = substr($time, -1);
$offset = ($time[0] == '-' ? -1 : 1) * $units[$unit] * $value;
return time() + $offset;
}
return (int)strtotime($time);
}
/**
* Get the ZFS pools for a device... just requires the device ID
* an empty return means ZFS is not in use or there are currently no pools
* @param $device_id
* @return array
*/
function get_zfs_pools($device_id)
{
$options=array(
'filter' => array(
'type' => array('=', 'zfs'),
),
);
$component=new LibreNMS\Component();
$zfsc=$component->getComponents($device_id, $options);
if (isset($zfsc[$device_id])) {
$id = $component->getFirstComponentID($zfsc, $device_id);
return json_decode($zfsc[$device_id][$id]['pools']);
}
return array();
}
/**
* Get the ports for a device... just requires the device ID
* an empty return means portsactivity is not in use or there are currently no ports
* @param $device_id
* @return array
*/
function get_portactivity_ports($device_id)
{
$options=array(
'filter' => array(
'type' => array('=', 'portsactivity'),
),
);
$component=new LibreNMS\Component();
$portsc=$component->getComponents($device_id, $options);
if (isset($portsc[$device_id])) {
$id = $component->getFirstComponentID($portsc, $device_id);
return json_decode($portsc[$device_id][$id]['ports']);
}
return array();
}
/**
* Returns the sysname of a device with a html line break prepended.
* if the device has an empty sysname it will return device's hostname instead
* And finally if the device has no hostname it will return an empty string
* @param array device
* @return string
*/
function get_device_name($device)
{
$ret_str = '';
if (format_hostname($device) !== $device['sysName']) {
$ret_str = $device['sysName'];
} elseif ($device['hostname'] !== $device['ip']) {
$ret_str = $device['hostname'];
}
return $ret_str;
}
/**
* Returns state generic label from value with optional text
*/
function get_state_label($sensor)
{
$state_translation = dbFetchRow('SELECT * FROM state_translations as ST, sensors_to_state_indexes as SSI WHERE ST.state_index_id=SSI.state_index_id AND SSI.sensor_id = ? AND ST.state_value = ? ', array($sensor['sensor_id'], $sensor['sensor_current']));
switch ($state_translation['state_generic_value']) {
case 0: // OK
$state_text = $state_translation['state_descr'] ?: "OK";
$state_label = "label-success";
break;
case 1: // Warning
$state_text = $state_translation['state_descr'] ?: "Warning";
$state_label = "label-warning";
break;
case 2: // Critical
$state_text = $state_translation['state_descr'] ?: "Critical";
$state_label = "label-danger";
break;
case 3: // Unknown
default:
$state_text = $state_translation['state_descr'] ?: "Unknown";
$state_label = "label-default";
}
return "$state_text";
}
/**
* Get sensor label and state color
* @param array $sensor
* @param string $type sensors or wireless
* @return string
*/
function get_sensor_label_color($sensor, $type = 'sensors')
{
$label_style = "label-success";
if (is_null($sensor)) {
return "label-unknown";
}
if (!is_null($sensor['sensor_limit_warn']) && $sensor['sensor_current'] > $sensor['sensor_limit_warn']) {
$label_style = "label-warning";
}
if (!is_null($sensor['sensor_limit_low_warn']) && $sensor['sensor_current'] < $sensor['sensor_limit_low_warn']) {
$label_style = "label-warning";
}
if (!is_null($sensor['sensor_limit']) && $sensor['sensor_current'] > $sensor['sensor_limit']) {
$label_style = "label-danger";
}
if (!is_null($sensor['sensor_limit_low']) && $sensor['sensor_current'] < $sensor['sensor_limit_low']) {
$label_style = "label-danger";
}
$unit = __("$type.{$sensor['sensor_class']}.unit");
if ($sensor['sensor_class'] == 'runtime') {
$sensor['sensor_current'] = formatUptime($sensor['sensor_current'] * 60, 'short');
return "".trim($sensor['sensor_current'])."";
}
return "".trim(format_si($sensor['sensor_current']).$unit)."";
}
/**
* @params int unix time
* @params int seconds
* @return int
*
* Rounds down to the nearest interval.
*
* The first argument is required and it is the unix time being
* rounded down.
*
* The second value is the time interval. If not specified, it
* defaults to 300, or 5 minutes.
*/
function lowest_time($time, $seconds = 300)
{
return $time - ($time % $seconds);
}
/**
* @params int
* @return string
*
* This returns the subpath for working with nfdump.
*
* 1 value is taken and that is a unix time stamp. It will be then be rounded
* off to the lowest five minutes earlier.
*
* The return string will be a path partial you can use with nfdump to tell it what
* file or range of files to use.
*
* Below ie a explanation of the layouts as taken from the NfSen config file.
* 0 no hierachy levels - flat layout - compatible with pre NfSen version
* 1 %Y/%m/%d year/month/day
* 2 %Y/%m/%d/%H year/month/day/hour
* 3 %Y/%W/%u year/week_of_year/day_of_week
* 4 %Y/%W/%u/%H year/week_of_year/day_of_week/hour
* 5 %Y/%j year/day-of-year
* 6 %Y/%j/%H year/day-of-year/hour
* 7 %Y-%m-%d year-month-day
* 8 %Y-%m-%d/%H year-month-day/hour
*/
function time_to_nfsen_subpath($time)
{
$time=lowest_time($time);
$layout=Config::get('nfsen_subdirlayout');
if ($layout == 0) {
return 'nfcapd.'.date('YmdHi', $time);
} elseif ($layout == 1) {
return date('Y\/m\/d\/\n\f\c\a\p\d\.YmdHi', $time);
} elseif ($layout == 2) {
return date('Y\/m\/d\/H\/\n\f\c\a\p\d\.YmdHi', $time);
} elseif ($layout == 3) {
return date('Y\/W\/w\/\n\f\c\a\p\d\.YmdHi', $time);
} elseif ($layout == 4) {
return date('Y\/W\/w\/H\/\n\f\c\a\p\d\.YmdHi', $time);
} elseif ($layout == 5) {
return date('Y\/z\/\n\f\c\a\p\d\.YmdHi', $time);
} elseif ($layout == 6) {
return date('Y\/z\/H\/\n\f\c\a\p\d\.YmdHi', $time);
} elseif ($layout == 7) {
return date('Y\-m\-d\/\n\f\c\a\p\d\.YmdHi', $time);
} elseif ($layout == 8) {
return date('Y\-m\-d\/H\/\n\f\c\a\p\d\.YmdHi', $time);
}
}
/**
* @params string hostname
* @return string
*
* Takes a hostname and transforms it to the name
* used by nfsen.
*/
function nfsen_hostname($hostname)
{
$nfsen_hostname=str_replace('.', Config::get('nfsen_split_char'), $hostname);
if (!is_null(Config::get('nfsen_suffix'))) {
$nfsen_hostname=str_replace(Config::get('nfsen_suffix'), '', $nfsen_hostname);
}
return $nfsen_hostname;
}
/**
* @params string hostname
* @return string
*
* Takes a hostname and returns the path to the nfsen
* live dir.
*/
function nfsen_live_dir($hostname)
{
$hostname=nfsen_hostname($hostname);
foreach (Config::get('nfsen_base') as $base_dir) {
if (file_exists($base_dir) && is_dir($base_dir)) {
return $base_dir.'/profiles-data/live/'.$hostname;
}
}
}