2009-09-07 11:07:59 +00:00
< ? php
2015-06-14 18:00:21 +10:00
/*
* LibreNMS - Common Functions
*
* Original Observium version by : Adam Armstrong , Tom Laermans
* Copyright ( c ) 2009 - 2012 Adam Armstrong .
*
* Additions for LibreNMS by : Neil Lathwood , Paul Gear , Tim DuFrane
* Copyright ( c ) 2014 - 2015 Neil Lathwood < http :// www . lathwood . co . uk >
* Copyright ( c ) 2014 - 2015 Gear Consulting Pty Ltd < http :// libertysys . com . au />
*
* This program is free software : you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation , either version 3 of the License , or ( at your
* option ) any later version . Please see LICENSE . txt at the top level of
* the source code distribution for details .
*/
2009-05-07 13:47:51 +00:00
2017-08-08 14:14:58 -05:00
use LibreNMS\Config ;
2023-08-05 12:12:36 -05:00
use LibreNMS\Enum\Severity ;
2017-08-08 14:14:58 -05:00
use LibreNMS\Exceptions\InvalidIpException ;
2021-04-29 22:42:18 -05:00
use LibreNMS\Util\Debug ;
2017-08-08 14:14:58 -05:00
use LibreNMS\Util\IP ;
2021-05-13 13:00:56 -05:00
use LibreNMS\Util\Laravel ;
2020-10-29 20:02:26 +02:00
use Symfony\Component\Process\Process ;
2017-08-08 14:14:58 -05:00
2018-12-16 07:42:50 -06:00
/**
* Execute and snmp command , filter debug output unless - v is specified
*
2021-09-08 23:35:56 +02:00
* @ param array $command
2018-12-16 07:42:50 -06:00
* @ return null | string
*/
2016-08-28 12:32:58 -05:00
function external_exec ( $command )
{
2020-10-29 20:02:26 +02:00
$device = DeviceCache :: getPrimary ();
$proc = new Process ( $command );
2019-01-10 11:18:34 -06:00
$proc -> setTimeout ( Config :: get ( 'snmp.exec_timeout' , 1200 ));
2016-09-22 11:36:33 -05:00
2021-04-29 22:42:18 -05:00
if ( Debug :: isEnabled () && ! Debug :: isVerbose ()) {
2018-12-16 07:42:50 -06:00
$patterns = [
2019-01-28 15:41:50 -06:00
'/-c\' \'[\S]+\'/' ,
'/-u\' \'[\S]+\'/' ,
'/-U\' \'[\S]+\'/' ,
'/-A\' \'[\S]+\'/' ,
'/-X\' \'[\S]+\'/' ,
'/-P\' \'[\S]+\'/' ,
'/-H\' \'[\S]+\'/' ,
2022-03-14 05:51:55 +08:00
'/-y\' \'[\S]+\'/' ,
2018-12-16 07:42:50 -06:00
'/(udp|udp6|tcp|tcp6):([^:]+):([\d]+)/' ,
];
$replacements = [
2019-01-28 15:41:50 -06:00
'-c\' \'COMMUNITY\'' ,
'-u\' \'USER\'' ,
2019-01-29 07:40:15 -06:00
'-U\' \'USER\'' ,
2019-01-28 15:41:50 -06:00
'-A\' \'PASSWORD\'' ,
'-X\' \'PASSWORD\'' ,
'-P\' \'PASSWORD\'' ,
'-H\' \'HOSTNAME\'' ,
2022-03-14 05:51:55 +08:00
'-y\' \'KG_KEY\'' ,
2018-12-16 07:42:50 -06:00
'\1:HOSTNAME:\3' ,
];
$debug_command = preg_replace ( $patterns , $replacements , $proc -> getCommandLine ());
2016-09-22 11:36:33 -05:00
c_echo ( 'SNMP[%c' . $debug_command . " %n] \n " );
2021-04-29 22:42:18 -05:00
} elseif ( Debug :: isVerbose ()) {
2018-12-16 07:42:50 -06:00
c_echo ( 'SNMP[%c' . $proc -> getCommandLine () . " %n] \n " );
2016-01-17 14:39:17 +00:00
}
2018-12-16 07:42:50 -06:00
$proc -> run ();
$output = $proc -> getOutput ();
2016-01-17 14:39:17 +00:00
2020-10-29 20:02:26 +02:00
if ( $proc -> getExitCode ()) {
2020-10-30 05:14:33 -05:00
if ( Str :: startsWith ( $proc -> getErrorOutput (), 'Invalid authentication protocol specified' )) {
2023-08-05 12:12:36 -05:00
\App\Models\Eventlog :: log ( 'Unsupported SNMP authentication algorithm - ' . $proc -> getExitCode (), optional ( $device ) -> device_id , 'poller' , Severity :: Error );
2020-10-30 05:14:33 -05:00
} elseif ( Str :: startsWith ( $proc -> getErrorOutput (), 'Invalid privacy protocol specified' )) {
2023-08-05 12:12:36 -05:00
\App\Models\Eventlog :: log ( 'Unsupported SNMP privacy algorithm - ' . $proc -> getExitCode (), optional ( $device ) -> device_id , 'poller' , Severity :: Error );
2020-10-30 05:14:33 -05:00
}
2020-10-29 20:02:26 +02:00
d_echo ( 'Exitcode: ' . $proc -> getExitCode ());
d_echo ( $proc -> getErrorOutput ());
}
2021-04-29 22:42:18 -05:00
if ( Debug :: isEnabled () && ! Debug :: isVerbose ()) {
2016-09-22 11:36:33 -05:00
$ip_regex = '/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/' ;
$debug_output = preg_replace ( $ip_regex , '*' , $output );
d_echo ( $debug_output . PHP_EOL );
2021-04-29 22:42:18 -05:00
} elseif ( Debug :: isVerbose ()) {
2016-09-22 11:36:33 -05:00
d_echo ( $output . PHP_EOL );
2016-01-17 14:39:17 +00:00
}
2018-12-16 07:42:50 -06:00
d_echo ( $proc -> getErrorOutput ());
2011-09-22 18:28:00 +00:00
return $output ;
}
2016-08-28 12:32:58 -05:00
function shorthost ( $hostname , $len = 12 )
{
2014-03-28 13:05:39 -04:00
// IP addresses should not be shortened
2016-08-28 12:32:58 -05:00
if ( filter_var ( $hostname , FILTER_VALIDATE_IP )) {
2014-03-28 13:04:44 -04:00
return $hostname ;
2016-08-28 12:32:58 -05:00
}
2017-11-09 20:47:52 +00:00
$len = Config :: get ( 'shorthost_target_length' , $len );
2015-07-13 20:10:26 +02:00
2011-09-22 15:54:16 +00:00
$parts = explode ( '.' , $hostname );
$shorthost = $parts [ 0 ];
$i = 1 ;
while ( $i < count ( $parts ) && strlen ( $shorthost . '.' . $parts [ $i ]) < $len ) {
$shorthost = $shorthost . '.' . $parts [ $i ];
$i ++ ;
}
2020-09-21 15:40:17 +02:00
2011-09-22 15:54:16 +00:00
return $shorthost ;
}
2015-07-13 20:10:26 +02:00
2016-08-28 12:32:58 -05:00
function print_error ( $text )
{
2021-05-13 13:00:56 -05:00
if ( Laravel :: isCli ()) {
2016-08-16 19:52:36 -05:00
c_echo ( '%r' . $text . " %n \n " );
2016-08-28 12:32:58 -05:00
} else {
2016-09-21 15:00:17 -04:00
echo '<div class="alert alert-danger"><i class="fa fa-fw fa-exclamation-circle" aria-hidden="true"></i> ' . $text . '</div>' ;
2011-09-08 12:24:18 +00:00
}
}
2016-08-28 12:32:58 -05:00
function print_message ( $text )
{
2021-05-13 13:00:56 -05:00
if ( Laravel :: isCli ()) {
2016-08-16 19:52:36 -05:00
c_echo ( '%g' . $text . " %n \n " );
2016-08-28 12:32:58 -05:00
} else {
2016-09-22 08:09:31 -04:00
echo '<div class="alert alert-success"><i class="fa fa-fw fa-check-circle" aria-hidden="true"></i> ' . $text . '</div>' ;
2011-09-08 12:24:18 +00:00
}
}
2016-07-08 22:58:36 -05:00
function get_sensor_rrd ( $device , $sensor )
{
2021-03-28 17:25:30 -05:00
return Rrd :: name ( $device [ 'hostname' ], get_sensor_rrd_name ( $device , $sensor ));
2016-07-08 22:58:36 -05:00
}
2016-08-28 12:32:58 -05:00
function get_sensor_rrd_name ( $device , $sensor )
{
2011-04-28 21:12:16 +00:00
// For IPMI, sensors tend to change order, and there is no index, so we prefer to use the description as key here.
2019-06-23 00:29:12 -05:00
if ( Config :: getOsSetting ( $device [ 'os' ], 'sensor_descr' ) || $sensor [ 'poller_type' ] == 'ipmi' ) {
2016-07-08 22:58:36 -05:00
return [ 'sensor' , $sensor [ 'sensor_class' ], $sensor [ 'sensor_type' ], $sensor [ 'sensor_descr' ]];
2016-07-07 01:33:43 -05:00
} else {
2016-07-08 22:58:36 -05:00
return [ 'sensor' , $sensor [ 'sensor_class' ], $sensor [ 'sensor_type' ], $sensor [ 'sensor_index' ]];
2011-04-26 15:07:52 +00:00
}
2016-07-07 01:33:43 -05:00
}
2016-08-28 12:32:58 -05:00
function get_port_rrdfile_path ( $hostname , $port_id , $suffix = '' )
{
2021-03-28 17:25:30 -05:00
return Rrd :: name ( $hostname , Rrd :: portName ( $port_id , $suffix ));
2016-01-26 13:49:30 +01:00
}
2016-08-28 12:32:58 -05:00
function get_port_by_index_cache ( $device_id , $ifIndex )
{
2011-05-19 10:02:55 +00:00
global $port_index_cache ;
if ( isset ( $port_index_cache [ $device_id ][ $ifIndex ]) && is_array ( $port_index_cache [ $device_id ][ $ifIndex ])) {
$port = $port_index_cache [ $device_id ][ $ifIndex ];
2016-08-28 12:32:58 -05:00
} else {
2011-05-19 10:02:55 +00:00
$port = get_port_by_ifIndex ( $device_id , $ifIndex );
$port_index_cache [ $device_id ][ $ifIndex ] = $port ;
}
return $port ;
}
2016-08-28 12:32:58 -05:00
function get_port_by_ifIndex ( $device_id , $ifIndex )
{
2011-05-19 10:02:55 +00:00
return dbFetchRow ( 'SELECT * FROM `ports` WHERE `device_id` = ? AND `ifIndex` = ?' , [ $device_id , $ifIndex ]);
}
2016-08-28 12:32:58 -05:00
function get_port_by_id ( $port_id )
{
2012-05-16 13:25:50 +00:00
if ( is_numeric ( $port_id )) {
2012-05-16 16:24:43 +00:00
$port = dbFetchRow ( 'SELECT * FROM `ports` WHERE `port_id` = ?' , [ $port_id ]);
2015-02-22 19:28:09 +00:00
if ( is_array ( $port )) {
2012-05-16 13:25:50 +00:00
return $port ;
2016-08-28 12:32:58 -05:00
} else {
return false ;
2015-07-13 20:10:26 +02:00
}
}
2011-05-19 10:02:55 +00:00
}
2016-08-28 12:32:58 -05:00
function get_device_id_by_port_id ( $port_id )
{
2011-03-23 09:54:56 +00:00
if ( is_numeric ( $port_id )) {
2011-05-12 17:59:00 +00:00
$device_id = dbFetchCell ( 'SELECT `device_id` FROM `ports` WHERE `port_id` = ?' , [ $port_id ]);
2015-02-22 19:28:09 +00:00
if ( is_numeric ( $device_id )) {
return $device_id ;
2016-08-28 12:32:58 -05:00
} else {
return false ;
2015-07-13 20:10:26 +02:00
}
2015-02-22 19:28:09 +00:00
}
2010-08-01 14:17:06 +00:00
}
2016-08-28 12:32:58 -05:00
function ifclass ( $ifOperStatus , $ifAdminStatus )
{
2018-12-07 16:24:53 -06:00
// fake a port model
return \LibreNMS\Util\Url :: portLinkDisplayClass (( object ) [ 'ifOperStatus' => $ifOperStatus , 'ifAdminStatus' => $ifAdminStatus ]);
2010-07-28 19:43:02 +00:00
}
2015-07-13 20:10:26 +02:00
2019-11-14 21:56:06 +00:00
function device_by_name ( $name )
2016-08-28 12:32:58 -05:00
{
2019-11-14 21:56:06 +00:00
return device_by_id_cache ( getidbyname ( $name ));
2011-10-03 13:40:37 +00:00
}
2016-08-28 12:32:58 -05:00
function accesspoint_by_id ( $ap_id , $refresh = '0' )
{
2015-02-18 21:31:01 +00:00
$ap = dbFetchRow ( 'SELECT * FROM `access_points` WHERE `accesspoint_id` = ?' , [ $ap_id ]);
2012-05-21 18:17:23 +00:00
return $ap ;
}
2017-12-20 08:36:49 -06:00
function device_by_id_cache ( $device_id , $refresh = false )
2016-08-28 12:32:58 -05:00
{
2020-09-11 14:28:46 +02:00
$model = $refresh ? DeviceCache :: refresh (( int ) $device_id ) : DeviceCache :: get (( int ) $device_id );
2011-03-11 18:03:49 +00:00
2019-11-14 21:56:06 +00:00
$device = $model -> toArray ();
2020-09-11 14:28:46 +02:00
$device [ 'location' ] = $model -> location -> location ? ? null ;
$device [ 'lat' ] = $model -> location -> lat ? ? null ;
$device [ 'lng' ] = $model -> location -> lng ? ? null ;
2016-08-28 12:32:58 -05:00
2011-03-23 09:54:56 +00:00
return $device ;
2010-04-20 15:46:17 +00:00
}
2016-08-28 12:32:58 -05:00
function truncate ( $substring , $max = 50 , $rep = '...' )
{
2011-09-20 14:37:54 +00:00
if ( strlen ( $substring ) < 1 ) {
$string = $rep ;
2016-08-28 12:32:58 -05:00
} else {
2011-09-20 14:37:54 +00:00
$string = $substring ;
}
2016-08-28 12:32:58 -05:00
$leave = $max - strlen ( $rep );
2011-09-20 14:37:54 +00:00
if ( strlen ( $string ) > $max ) {
return substr_replace ( $string , $rep , $leave );
2016-08-28 12:32:58 -05:00
} else {
2011-09-20 14:37:54 +00:00
return $string ;
}
2009-10-28 13:49:37 +00:00
}
2019-11-14 21:56:06 +00:00
function gethostbyid ( $device_id )
2016-08-28 12:32:58 -05:00
{
2020-09-11 14:28:46 +02:00
return DeviceCache :: get (( int ) $device_id ) -> hostname ;
2009-05-07 13:47:51 +00:00
}
2016-08-28 12:32:58 -05:00
function strgen ( $length = 16 )
{
2011-03-23 09:54:56 +00:00
$entropy = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 'a' , 'A' , 'b' , 'B' , 'c' , 'C' , 'd' , 'D' , 'e' ,
'E' , 'f' , 'F' , 'g' , 'G' , 'h' , 'H' , 'i' , 'I' , 'j' , 'J' , 'k' , 'K' , 'l' , 'L' , 'm' , 'M' , 'n' ,
'N' , 'o' , 'O' , 'p' , 'P' , 'q' , 'Q' , 'r' , 'R' , 's' , 'S' , 't' , 'T' , 'u' , 'U' , 'v' , 'V' , 'w' ,
'W' , 'x' , 'X' , 'y' , 'Y' , 'z' , 'Z' , ];
$string = '' ;
2011-03-11 18:03:49 +00:00
2011-03-23 09:54:56 +00:00
for ( $i = 0 ; $i < $length ; $i ++ ) {
2016-08-28 12:32:58 -05:00
$key = mt_rand ( 0 , 61 );
2011-03-23 09:54:56 +00:00
$string .= $entropy [ $key ];
}
2011-03-11 18:03:49 +00:00
2011-03-23 09:54:56 +00:00
return $string ;
2009-05-07 13:47:51 +00:00
}
2016-08-28 12:32:58 -05:00
function getifbyid ( $id )
{
2012-05-16 13:25:50 +00:00
return dbFetchRow ( 'SELECT * FROM `ports` WHERE `port_id` = ?' , [ $id ]);
2010-01-08 23:09:25 +00:00
}
2016-08-28 12:32:58 -05:00
function getidbyname ( $hostname )
{
2019-11-14 21:56:06 +00:00
return DeviceCache :: getByHostname ( $hostname ) -> device_id ;
2009-05-07 13:47:51 +00:00
}
2016-08-28 12:32:58 -05:00
function zeropad ( $num , $length = 2 )
{
2017-08-08 14:14:58 -05:00
return str_pad ( $num , $length , '0' , STR_PAD_LEFT );
2011-03-28 20:29:34 +00:00
}
2016-08-28 12:32:58 -05:00
function set_dev_attrib ( $device , $attrib_type , $attrib_value )
{
2024-01-19 16:14:29 +01:00
return DeviceCache :: get (( int ) $device [ 'device_id' ]) -> setAttrib ( $attrib_type , $attrib_value );
2011-03-31 17:19:54 +00:00
}
2019-11-14 21:56:06 +00:00
function get_dev_attribs ( $device_id )
2016-08-28 12:32:58 -05:00
{
2020-09-11 14:28:46 +02:00
return DeviceCache :: get (( int ) $device_id ) -> getAttribs ();
2011-05-03 20:13:15 +00:00
}
2019-11-14 21:56:06 +00:00
function get_dev_attrib ( $device , $attrib_type )
2016-08-28 12:32:58 -05:00
{
2020-09-11 14:28:46 +02:00
return DeviceCache :: get (( int ) $device [ 'device_id' ]) -> getAttrib ( $attrib_type );
2015-06-13 09:26:26 +10:00
}
2016-08-28 12:32:58 -05:00
function del_dev_attrib ( $device , $attrib_type )
{
2020-09-11 14:28:46 +02:00
return DeviceCache :: get (( int ) $device [ 'device_id' ]) -> forgetAttrib ( $attrib_type );
2011-03-31 17:19:54 +00:00
}
2011-03-28 20:29:34 +00:00
2016-08-16 19:52:36 -05:00
/**
* Output using console color if possible
* https :// github . com / pear / Console_Color2 / blob / master / examples / documentation
*
2021-09-08 23:35:56 +02:00
* @ param string $string the string to print with console color
* @ param bool $enabled if set to false , this function does nothing
2016-08-16 19:52:36 -05:00
*/
2016-08-17 16:00:43 -05:00
function c_echo ( $string , $enabled = true )
2016-08-16 19:52:36 -05:00
{
2016-08-28 12:32:58 -05:00
if ( ! $enabled ) {
2016-08-17 16:00:43 -05:00
return ;
}
2016-08-16 19:52:36 -05:00
2021-05-13 13:00:56 -05:00
if ( Laravel :: isCli ()) {
2017-07-17 13:02:28 -05:00
global $console_color ;
if ( $console_color ) {
echo $console_color -> convert ( $string );
} else {
// limited functionality for validate.php
$search = [
'/%n/' ,
'/%g/' ,
'/%R/' ,
'/%Y/' ,
'/%B/' ,
'/%((%)|.)/' , // anything left over replace with empty string
];
$replace = [
" \ e[0m " ,
" \ e[32m " ,
" \ e[1;31m " ,
" \ e[1;33m " ,
" \ e[1;34m " ,
'' ,
];
echo preg_replace ( $search , $replace , $string );
}
2016-08-16 19:52:36 -05:00
} else {
echo preg_replace ( '/%((%)|.)/' , '' , $string );
}
}
2015-06-13 22:50:37 +10:00
/*
* @ return true if client IP address is authorized to access graphs
*/
2016-08-28 12:32:58 -05:00
function is_client_authorized ( $clientip )
{
2017-08-08 14:14:58 -05:00
if ( Config :: get ( 'allow_unauth_graphs' , false )) {
2015-06-13 22:50:37 +10:00
d_echo ( " Unauthorized graphs allowed \n " );
2020-09-21 15:40:17 +02:00
2015-06-13 22:50:37 +10:00
return true ;
}
2017-08-08 14:14:58 -05:00
foreach ( Config :: get ( 'allow_unauth_graphs_cidr' , []) as $range ) {
try {
if ( IP :: parse ( $clientip ) -> inNetwork ( $range )) {
2015-06-13 22:50:37 +10:00
d_echo ( " Unauthorized graphs allowed from $range\n " );
2020-09-21 15:40:17 +02:00
2015-06-13 22:50:37 +10:00
return true ;
}
2017-08-08 14:14:58 -05:00
} catch ( InvalidIpException $e ) {
d_echo ( " Client IP ( $clientip ) is invalid. \n " );
2015-06-13 22:50:37 +10:00
}
}
return false ;
2015-11-15 18:18:13 +10:00
} // is_client_authorized
2015-06-13 22:55:18 +10:00
/*
* @ return an array of all graph subtypes for the given type
*/
2016-01-17 15:00:15 +10:00
function get_graph_subtypes ( $type , $device = null )
{
2019-04-11 23:26:42 -05:00
$type = basename ( $type );
2015-06-13 22:55:18 +10:00
$types = [];
// find the subtypes defined in files
2019-06-23 00:29:12 -05:00
if ( $handle = opendir ( Config :: get ( 'install_dir' ) . " /includes/html/graphs/ $type / " )) {
2015-06-13 22:55:18 +10:00
while ( false !== ( $file = readdir ( $handle ))) {
if ( $file != '.' && $file != '..' && $file != 'auth.inc.php' && strstr ( $file , '.inc.php' )) {
$types [] = str_replace ( '.inc.php' , '' , $file );
}
}
closedir ( $handle );
}
sort ( $types );
2020-09-21 15:40:17 +02:00
2015-06-13 22:55:18 +10:00
return $types ;
2015-11-15 18:18:13 +10:00
} // get_graph_subtypes
2016-08-28 12:32:58 -05:00
function generate_smokeping_file ( $device , $file = '' )
{
2020-09-11 14:28:46 +02:00
$smokeping = new \LibreNMS\Util\Smokeping ( DeviceCache :: get (( int ) $device [ 'device_id' ]));
2020-09-21 15:40:17 +02:00
2020-04-29 07:25:13 -05:00
return $smokeping -> generateFileName ( $file );
}
2015-11-15 18:18:13 +10:00
2015-07-21 17:08:09 +02:00
/*
* @ return rounded value to 10 th / 100 th / 1000 th depending on input ( valid : 10 , 100 , 1000 )
*/
2016-08-28 12:32:58 -05:00
function round_Nth ( $val , $round_to )
{
2015-07-21 17:08:09 +02:00
if (( $round_to == '10' ) || ( $round_to == '100' ) || ( $round_to == '1000' )) {
$diff = $val % $round_to ;
if ( $diff >= ( $round_to / 2 )) {
$ret = $val + ( $round_to - $diff );
} else {
$ret = $val - $diff ;
}
2020-09-21 15:40:17 +02:00
2015-07-21 17:08:09 +02:00
return $ret ;
}
2016-08-28 12:32:58 -05:00
} // end round_Nth
2015-07-21 17:08:09 +02:00
2019-12-19 01:17:21 +01:00
function is_customoid_graph ( $type , $subtype )
{
if ( ! empty ( $subtype ) && $type == 'customoid' ) {
return true ;
}
2020-09-21 15:40:17 +02:00
2019-12-19 01:17:21 +01:00
return false ;
} // is_customoid_graph
2015-07-01 08:14:23 +10:00
2015-11-16 18:50:52 -08:00
/**
* Parse location field for coordinates
2021-09-10 20:09:53 +02:00
*
2015-11-16 18:50:52 -08:00
* @ param string location The location field to look for coords in .
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls)
- Parse coordinates from the location more consistently
- Add settings to webui
- ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~
- Google Maps, Bing, Mapquest, and OpenStreetMap supported initially.
- Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though.
- All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate)
- Update all (I think) sql queries to handle the new structure
- Remove final vestiges of override_sysLocation as a device attribute
- Update existing device groups and rules in DB
- Tested all APIs with good/bad location, no/bad/good key, and no connection.
- Cannot fix advanced queries that use location
This blocks #8868
DO NOT DELETE THIS TEXT
#### Please note
> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.
- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)
#### Testers
If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
2018-11-28 16:49:18 -06:00
* @ return array | bool Containing the lat and lng coords
2018-08-05 03:50:13 -05:00
**/
2016-08-28 12:32:58 -05:00
function parse_location ( $location )
{
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls)
- Parse coordinates from the location more consistently
- Add settings to webui
- ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~
- Google Maps, Bing, Mapquest, and OpenStreetMap supported initially.
- Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though.
- All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate)
- Update all (I think) sql queries to handle the new structure
- Remove final vestiges of override_sysLocation as a device attribute
- Update existing device groups and rules in DB
- Tested all APIs with good/bad location, no/bad/good key, and no connection.
- Cannot fix advanced queries that use location
This blocks #8868
DO NOT DELETE THIS TEXT
#### Please note
> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.
- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)
#### Testers
If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
2018-11-28 16:49:18 -06:00
preg_match ( '/\[(-?[0-9. ]+), *(-?[0-9. ]+)\]/' , $location , $tmp_loc );
if ( is_numeric ( $tmp_loc [ 1 ]) && is_numeric ( $tmp_loc [ 2 ])) {
return [ 'lat' => $tmp_loc [ 1 ], 'lng' => $tmp_loc [ 2 ]];
2015-11-16 18:50:52 -08:00
}
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls)
- Parse coordinates from the location more consistently
- Add settings to webui
- ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~
- Google Maps, Bing, Mapquest, and OpenStreetMap supported initially.
- Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though.
- All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate)
- Update all (I think) sql queries to handle the new structure
- Remove final vestiges of override_sysLocation as a device attribute
- Update existing device groups and rules in DB
- Tested all APIs with good/bad location, no/bad/good key, and no connection.
- Cannot fix advanced queries that use location
This blocks #8868
DO NOT DELETE THIS TEXT
#### Please note
> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.
- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)
#### Testers
If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
2018-11-28 16:49:18 -06:00
return false ;
2015-11-16 18:50:52 -08:00
} //end parse_location()
2016-01-06 00:14:35 +00:00
2016-01-17 23:59:51 +00:00
/**
2018-08-05 03:50:13 -05:00
* Convert a MySQL binary v4 ( 4 - byte ) or v6 ( 16 - byte ) IP address to a printable string .
2021-09-10 20:09:53 +02:00
*
2021-09-08 23:35:56 +02:00
* @ param string $ip A binary string containing an IP address , as returned from MySQL ' s INET6_ATON function
2018-08-05 03:50:13 -05:00
* @ return string Empty if not valid .
*/
2021-02-09 00:29:04 +01:00
// Fuction is from https://php.net/manual/en/function.inet-ntop.php
2016-08-28 12:32:58 -05:00
function inet6_ntop ( $ip )
{
2016-01-17 23:59:51 +00:00
$l = strlen ( $ip );
if ( $l == 4 or $l == 16 ) {
return inet_ntop ( pack ( 'A' . $l , $ip ));
}
2020-09-21 15:40:17 +02:00
2016-01-17 23:59:51 +00:00
return '' ;
}
2016-01-19 09:00:18 +00:00
2016-01-17 22:01:09 +00:00
/**
2017-05-05 12:25:58 +01:00
* If hostname is an ip , use return sysName
2021-09-10 20:09:53 +02:00
*
2021-09-08 23:35:56 +02:00
* @ param array $device ( uses hostname and sysName fields )
2016-01-17 22:01:09 +00:00
* @ return string
2018-07-02 15:23:09 +02:00
*/
2021-11-18 15:46:22 -06:00
function format_hostname ( $device ) : string
{
$hostname = $device [ 'hostname' ] ? ? 'invalid hostname' ;
$hostname_is_ip = IP :: isValid ( $hostname );
$sysName = empty ( $device [ 'sysName' ]) ? $hostname : $device [ 'sysName' ];
return \App\View\SimpleTemplate :: parse ( empty ( $device [ 'display' ]) ? Config :: get ( 'device_display_default' , '{{ $hostname }}' ) : $device [ 'display' ], [
'hostname' => $hostname ,
'sysName' => $sysName ,
'sysName_fallback' => $hostname_is_ip ? $sysName : $hostname ,
'ip' => empty ( $device [ 'overwrite_ip' ]) ? ( $hostname_is_ip ? $device [ 'hostname' ] : $device [ 'ip' ] ? ? '' ) : $device [ 'overwrite_ip' ],
]);
2018-07-02 15:23:09 +02:00
}
2016-01-26 13:49:30 +01:00
/**
* Query all ports of the given device ( by ID ) and build port array and
* port association maps for ifIndex , ifName , ifDescr . Query port stats
* if told to do so , too .
2021-09-10 20:09:53 +02:00
*
2021-09-08 23:35:56 +02:00
* @ param int $device_id ID of device to query ports for
* @ param bool $with_statistics Query port statistics , too . ( optional , default false )
2016-01-26 13:49:30 +01:00
* @ return array
*/
2016-08-28 12:32:58 -05:00
function get_ports_mapped ( $device_id , $with_statistics = false )
{
2016-01-30 10:05:46 +00:00
$ports = [];
2016-01-30 10:10:16 +00:00
$maps = [
2016-01-30 10:05:46 +00:00
'ifIndex' => [],
2024-01-05 05:39:12 +01:00
'ifName' => [],
2016-01-30 10:05:46 +00:00
'ifDescr' => [],
];
2016-01-26 13:49:30 +01:00
if ( $with_statistics ) {
/* ... including any related ports_statistics if requested */
$query = 'SELECT *, `ports_statistics`.`port_id` AS `ports_statistics_port_id`, `ports`.`port_id` AS `port_id` FROM `ports` LEFT OUTER JOIN `ports_statistics` ON `ports`.`port_id` = `ports_statistics`.`port_id` WHERE `ports`.`device_id` = ? ORDER BY ports.port_id' ;
2016-10-15 02:03:26 +01:00
} else {
/* Query all information available for ports for this device ... */
$query = 'SELECT * FROM `ports` WHERE `device_id` = ? ORDER BY port_id' ;
2016-01-26 13:49:30 +01:00
}
// Query known ports in order of discovery to make sure the latest
// discoverd/polled port is in the mapping tables.
2016-08-28 12:32:58 -05:00
foreach ( dbFetchRows ( $query , [ $device_id ]) as $port ) {
2016-01-26 13:49:30 +01:00
// Store port information by ports port_id from DB
$ports [ $port [ 'port_id' ]] = $port ;
// Build maps from ifIndex, ifName, ifDescr to port_id
$maps [ 'ifIndex' ][ $port [ 'ifIndex' ]] = $port [ 'port_id' ];
$maps [ 'ifName' ][ $port [ 'ifName' ]] = $port [ 'port_id' ];
$maps [ 'ifDescr' ][ $port [ 'ifDescr' ]] = $port [ 'port_id' ];
}
2016-01-30 10:05:46 +00:00
return [
2016-01-26 13:49:30 +01:00
'ports' => $ports ,
2024-01-05 05:39:12 +01:00
'maps' => $maps ,
2016-01-30 10:05:46 +00:00
];
2016-01-26 13:49:30 +01:00
}
/**
* Calculate port_id of given port using given devices port information and port association mode
2021-09-10 20:09:53 +02:00
*
2021-09-08 23:35:56 +02:00
* @ param array $ports_mapped Port information of device queried by get_ports_mapped ()
* @ param array $port Port information as fetched from DB
* @ param string $port_association_mode Port association mode to use for mapping
2016-01-26 13:49:30 +01:00
* @ return int port_id ( or Null )
*/
2016-08-28 12:32:58 -05:00
function get_port_id ( $ports_mapped , $port , $port_association_mode )
{
2016-01-26 13:49:30 +01:00
// Get port_id according to port_association_mode used for this device
2016-08-28 12:32:58 -05:00
$port_id = null ;
2016-01-26 13:49:30 +01:00
/*
* Information an all ports is available through $ports_mapped [ 'ports' ]
* This might come in handy sometime in the future to add you nifty new
* port mapping schema :
*
* $ports = $ports_mapped [ 'ports' ];
*/
$maps = $ports_mapped [ 'maps' ];
2016-08-28 12:32:58 -05:00
if ( in_array ( $port_association_mode , [ 'ifIndex' , 'ifName' , 'ifDescr' , 'ifAlias' ])) {
2022-10-25 19:27:28 +02:00
$port_id = $maps [ $port_association_mode ][ $port [ $port_association_mode ]] ? ? null ;
2016-01-26 13:49:30 +01:00
}
return $port_id ;
}
2016-06-22 08:42:48 +00:00
/**
* Create a glue - chain
2021-09-10 20:09:53 +02:00
*
2021-09-08 23:35:56 +02:00
* @ param array $tables Initial Tables to construct glue - chain
* @ param string $target Glue to find ( usual device_id )
* @ param int $x Recursion Anchor
* @ param array $hist History of processed tables
* @ param array $last Glues on the fringe
2017-12-02 17:03:36 -06:00
* @ return array | false
2016-06-22 08:42:48 +00:00
*/
2016-08-28 12:32:58 -05:00
function ResolveGlues ( $tables , $target , $x = 0 , $hist = [], $last = [])
{
if ( sizeof ( $tables ) == 1 && $x != 0 ) {
if ( dbFetchCell ( 'SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME = ?' , [ $tables [ 0 ], $target ]) == 1 ) {
return array_merge ( $last , [ $tables [ 0 ] . '.' . $target ]);
} else {
2016-06-22 08:42:48 +00:00
return false ;
}
2016-08-28 12:32:58 -05:00
} else {
2016-06-22 08:42:48 +00:00
$x ++ ;
2016-08-28 12:32:58 -05:00
if ( $x > 30 ) {
2016-06-22 08:42:48 +00:00
//Too much recursion. Abort.
return false ;
}
2016-08-28 12:32:58 -05:00
foreach ( $tables as $table ) {
2017-12-02 17:03:36 -06:00
if ( $table == 'state_translations' && ( $target == 'device_id' || $target == 'sensor_id' )) {
// workaround for state_translations
2017-12-06 16:13:10 -06:00
return array_merge ( $last , [
2017-12-02 17:03:36 -06:00
'state_translations.state_index_id' ,
'sensors_to_state_indexes.sensor_id' ,
" sensors. $target " ,
2017-12-06 16:13:10 -06:00
]);
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls)
- Parse coordinates from the location more consistently
- Add settings to webui
- ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~
- Google Maps, Bing, Mapquest, and OpenStreetMap supported initially.
- Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though.
- All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate)
- Update all (I think) sql queries to handle the new structure
- Remove final vestiges of override_sysLocation as a device attribute
- Update existing device groups and rules in DB
- Tested all APIs with good/bad location, no/bad/good key, and no connection.
- Cannot fix advanced queries that use location
This blocks #8868
DO NOT DELETE THIS TEXT
#### Please note
> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.
- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)
#### Testers
If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
2018-11-28 16:49:18 -06:00
} elseif ( $table == 'application_metrics' && $target == 'device_id' ) {
2017-12-06 16:13:10 -06:00
return array_merge ( $last , [
'application_metrics.app_id' ,
" applications. $target " ,
]);
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls)
- Parse coordinates from the location more consistently
- Add settings to webui
- ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~
- Google Maps, Bing, Mapquest, and OpenStreetMap supported initially.
- Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though.
- All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate)
- Update all (I think) sql queries to handle the new structure
- Remove final vestiges of override_sysLocation as a device attribute
- Update existing device groups and rules in DB
- Tested all APIs with good/bad location, no/bad/good key, and no connection.
- Cannot fix advanced queries that use location
This blocks #8868
DO NOT DELETE THIS TEXT
#### Please note
> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.
- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)
#### Testers
If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
2018-11-28 16:49:18 -06:00
} elseif ( $table == 'locations' && $target == 'device_id' ) {
return array_merge ( $last , [
'locations.id' ,
'devices.device_id.location_id' ,
]);
2017-12-02 17:03:36 -06:00
}
2016-08-28 12:32:58 -05:00
$glues = dbFetchRows ( 'SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME LIKE "%\_id"' , [ $table ]);
if ( sizeof ( $glues ) == 1 && $glues [ 0 ][ 'COLUMN_NAME' ] != $target ) {
2016-06-22 08:42:48 +00:00
//Search for new candidates to expand
$ntables = [];
2020-05-19 14:35:32 -05:00
[ $tmp ] = explode ( '_' , $glues [ 0 ][ 'COLUMN_NAME' ], 2 );
2016-06-22 08:42:48 +00:00
$ntables [] = $tmp ;
$ntables [] = $tmp . 's' ;
2016-08-28 12:32:58 -05:00
$tmp = dbFetchRows ( 'SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME LIKE "' . substr ( $table , 0 , - 1 ) . '_%" && TABLE_NAME != "' . $table . '"' );
foreach ( $tmp as $expand ) {
2016-06-22 08:42:48 +00:00
$ntables [] = $expand [ 'TABLE_NAME' ];
}
2016-08-28 12:32:58 -05:00
$tmp = ResolveGlues ( $ntables , $target , $x ++ , array_merge ( $tables , $ntables ), array_merge ( $last , [ $table . '.' . $glues [ 0 ][ 'COLUMN_NAME' ]]));
if ( is_array ( $tmp )) {
2016-06-22 08:42:48 +00:00
return $tmp ;
}
2016-08-28 12:32:58 -05:00
} else {
foreach ( $glues as $glue ) {
if ( $glue [ 'COLUMN_NAME' ] == $target ) {
return array_merge ( $last , [ $table . '.' . $target ]);
} else {
2020-05-19 14:35:32 -05:00
[ $tmp ] = explode ( '_' , $glue [ 'COLUMN_NAME' ]);
2016-06-22 08:42:48 +00:00
$tmp .= 's' ;
2016-08-28 12:32:58 -05:00
if ( ! in_array ( $tmp , $tables ) && ! in_array ( $tmp , $hist )) {
2016-06-22 08:42:48 +00:00
//Expand table
2016-08-28 12:32:58 -05:00
$tmp = ResolveGlues ([ $tmp ], $target , $x ++ , array_merge ( $tables , [ $tmp ]), array_merge ( $last , [ $table . '.' . $glue [ 'COLUMN_NAME' ]]));
if ( is_array ( $tmp )) {
2016-06-22 08:42:48 +00:00
return $tmp ;
}
}
}
}
}
}
}
2024-01-05 05:39:12 +01:00
2016-06-22 08:42:48 +00:00
//You should never get here.
return false ;
}
2016-08-19 14:57:08 -05:00
/**
2018-01-29 15:58:21 -06:00
* Determine if a given string contains a given substring .
2016-08-19 14:57:08 -05:00
*
2021-09-08 23:35:56 +02:00
* @ param string $haystack
* @ param string | array $needles
2016-08-19 14:57:08 -05:00
* @ return bool
*/
2018-01-29 15:58:21 -06:00
function str_i_contains ( $haystack , $needles )
2016-08-19 14:57:08 -05:00
{
2018-01-29 15:58:21 -06:00
foreach (( array ) $needles as $needle ) {
if ( $needle != '' && stripos ( $haystack , $needle ) !== false ) {
return true ;
2016-08-19 14:57:08 -05:00
}
}
2020-09-21 15:40:17 +02:00
2016-08-19 14:57:08 -05:00
return false ;
}
2019-12-16 23:58:54 +01:00
/**
* Get alert_rules sql filter by minimal severity
*
2021-09-08 23:35:56 +02:00
* @ param string | int $min_severity
* @ param string $alert_rules_name
2019-12-16 23:58:54 +01:00
* @ return string
*/
function get_sql_filter_min_severity ( $min_severity , $alert_rules_name )
{
$alert_severities = [
// alert_rules.status is enum('ok','warning','critical')
'ok' => 1 ,
'warning' => 2 ,
'critical' => 3 ,
'ok only' => 4 ,
'warning only' => 5 ,
'critical only' => 6 ,
];
if ( is_numeric ( $min_severity )) {
$min_severity_id = $min_severity ;
} elseif ( ! empty ( $min_severity )) {
$min_severity_id = $alert_severities [ $min_severity ];
}
if ( isset ( $min_severity_id )) {
return " AND ` $alert_rules_name `.`severity` " . ( $min_severity_id > 3 ? '' : '>' ) . '= ' . ( $min_severity_id > 3 ? $min_severity_id - 3 : $min_severity_id );
}
2020-09-21 15:40:17 +02:00
2019-12-16 23:58:54 +01:00
return '' ;
}
2017-01-13 12:47:16 +00:00
/**
2017-08-28 12:57:23 -05:00
* Converts fahrenheit to celsius ( with 2 decimal places )
* if $scale is not fahrenheit , it assumes celsius and returns the value
*
2021-09-08 23:35:56 +02:00
* @ param float $value
* @ param string $scale fahrenheit or celsius
2017-08-28 12:57:23 -05:00
* @ return string ( containing a float )
2017-01-18 08:48:33 +00:00
*/
2017-08-28 12:57:23 -05:00
function fahrenheit_to_celsius ( $value , $scale = 'fahrenheit' )
2017-01-18 08:48:33 +00:00
{
if ( $scale === 'fahrenheit' ) {
$value = ( $value - 32 ) / 1.8 ;
}
2020-09-21 15:40:17 +02:00
2017-01-18 08:48:33 +00:00
return sprintf ( '%.02f' , $value );
}
2017-08-19 20:22:23 +01:00
2019-12-19 01:17:21 +01:00
/**
* Converts celsius to fahrenheit ( with 2 decimal places )
* if $scale is not celsius , it assumes celsius and returns the value
*
2021-09-08 23:35:56 +02:00
* @ param float $value
* @ param string $scale fahrenheit or celsius
2019-12-19 01:17:21 +01:00
* @ return string ( containing a float )
*/
function celsius_to_fahrenheit ( $value , $scale = 'celsius' )
{
if ( $scale === 'celsius' ) {
$value = ( $value * 1.8 ) + 32 ;
}
2020-09-21 15:40:17 +02:00
2019-12-19 01:17:21 +01:00
return sprintf ( '%.02f' , $value );
}
2024-02-18 18:30:42 +01:00
/**
* Converts kelvin to fahrenheit ( with 2 decimal places )
* if $scale is not celsius , it assumes celsius and returns the value
*
* @ param float $value
* @ param string $scale fahrenheit or celsius
* @ return string ( containing a float )
*/
function kelvin_to_celsius ( $value , $scale = 'celsius' )
{
if ( $scale === 'celsius' ) {
$value = $value - 273.15 ;
}
return sprintf ( '%.02f' , $value );
}
2020-09-14 07:03:35 +10:00
/**
* Converts string to float
*/
function string_to_float ( $value )
{
return sprintf ( '%.02f' , $value );
}
2018-09-19 17:00:11 +02:00
/**
* Converts uW to dBm
* $value must be positive
*/
2017-01-19 16:42:57 +00:00
function uw_to_dbm ( $value )
{
2024-09-23 10:11:05 -05:00
if ( $value < 0 ) {
return null ;
}
if ( $value == 0 ) {
return - 60 ;
}
return 10 * log10 ( $value / 1000 );
2017-01-19 16:42:57 +00:00
}
2018-09-19 17:00:11 +02:00
2020-09-08 23:07:04 +10:00
/**
* Converts mW to dBm
* $value must be positive
*/
function mw_to_dbm ( $value )
{
2024-09-23 10:11:05 -05:00
if ( $value < 0 ) {
return null ;
}
if ( $value == 0 ) {
return - 60 ;
}
return 10 * log10 ( $value );
2020-09-08 23:07:04 +10:00
}
2017-01-18 08:48:33 +00:00
/**
2023-06-13 13:35:00 +02:00
* @ param $value
2021-09-08 23:35:56 +02:00
* @ param null $default
* @ param int $min
2017-01-18 08:48:33 +00:00
* @ return null
*/
2017-03-08 04:15:22 +00:00
function set_null ( $value , $default = null , $min = null )
2017-01-18 08:48:33 +00:00
{
2018-07-13 17:08:00 -05:00
if ( ! is_numeric ( $value )) {
2017-09-07 14:49:32 +01:00
return $default ;
2018-07-13 17:08:00 -05:00
} elseif ( is_nan ( $value )) {
2017-09-07 14:49:32 +01:00
return $default ;
2018-07-13 17:08:00 -05:00
} elseif ( is_infinite ( $value )) {
2017-03-08 04:15:22 +00:00
return $default ;
} elseif ( isset ( $min ) && $value < $min ) {
return $default ;
2017-01-18 08:48:33 +00:00
}
2020-09-21 15:40:17 +02:00
2017-01-18 08:48:33 +00:00
return $value ;
}
/*
2017-01-13 12:47:16 +00:00
* @ param $value
* @ param int $default
* @ return int
*/
function set_numeric ( $value , $default = 0 )
{
2018-07-13 17:08:00 -05:00
if ( ! is_numeric ( $value ) ||
is_nan ( $value ) ||
is_infinite ( $value )
2017-09-07 14:49:32 +01:00
) {
2017-01-13 12:47:16 +00:00
$value = $default ;
}
2020-09-21 15:40:17 +02:00
2017-01-13 12:47:16 +00:00
return $value ;
}
2017-01-26 22:38:43 +00:00
function get_vm_parent_id ( $device )
{
if ( empty ( $device [ 'hostname' ])) {
return false ;
}
2019-06-23 00:29:12 -05:00
return dbFetchCell ( 'SELECT `device_id` FROM `vminfo` WHERE `vmwVmDisplayName` = ? OR `vmwVmDisplayName` = ?' , [ $device [ 'hostname' ], $device [ 'hostname' ] . '.' . Config :: get ( 'mydomain' )]);
2017-01-26 22:38:43 +00:00
}
2017-03-05 03:25:06 +00:00
2017-12-01 01:53:26 -06:00
/**
* Index an array by a column
*
2021-09-08 23:35:56 +02:00
* @ param array $array
* @ param string | int $column
2017-12-01 01:53:26 -06:00
* @ return array
*/
function array_by_column ( $array , $column )
{
return array_combine ( array_column ( $array , $column ), $array );
}