mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 01:26:11 -08:00
1142 lines
39 KiB
PHP
Executable File
1142 lines
39 KiB
PHP
Executable File
<?php
|
|
//------------------------------------------------------------------------------
|
|
// NetAlertX
|
|
// Open Source Network Guard / WIFI & LAN intrusion detector
|
|
//
|
|
// devices.php - Front module. Server side. Manage Devices
|
|
//------------------------------------------------------------------------------
|
|
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
|
|
//------------------------------------------------------------------------------
|
|
|
|
// External files
|
|
require dirname(__FILE__).'/init.php';
|
|
|
|
//------------------------------------------------------------------------------
|
|
// check if authenticated
|
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Action selector
|
|
//------------------------------------------------------------------------------
|
|
// Set maximum execution time to 15 seconds
|
|
|
|
ini_set ('max_execution_time','30');
|
|
|
|
// Action functions
|
|
if (isset ($_REQUEST['action']) && !empty ($_REQUEST['action'])) {
|
|
$action = $_REQUEST['action'];
|
|
switch ($action) {
|
|
case 'getServerDeviceData': getServerDeviceData(); break;
|
|
case 'setDeviceData': setDeviceData(); break;
|
|
case 'deleteDevice': deleteDevice(); break;
|
|
case 'deleteAllWithEmptyMACs': deleteAllWithEmptyMACs(); break;
|
|
|
|
case 'deleteAllDevices': deleteAllDevices(); break;
|
|
case 'deleteUnknownDevices': deleteUnknownDevices(); break;
|
|
case 'deleteEvents': deleteEvents(); break;
|
|
case 'deleteEvents30': deleteEvents30(); break;
|
|
case 'deleteActHistory': deleteActHistory(); break;
|
|
case 'deleteDeviceEvents': deleteDeviceEvents(); break;
|
|
case 'resetDeviceProps': resetDeviceProps(); break;
|
|
case 'PiaBackupDBtoArchive': PiaBackupDBtoArchive(); break;
|
|
case 'PiaRestoreDBfromArchive': PiaRestoreDBfromArchive(); break;
|
|
case 'PiaPurgeDBBackups': PiaPurgeDBBackups(); break;
|
|
case 'ExportCSV': ExportCSV(); break;
|
|
case 'ImportCSV': ImportCSV(); break;
|
|
|
|
case 'getDevicesTotals': getDevicesTotals(); break;
|
|
case 'getDevicesList': getDevicesList(); break;
|
|
case 'getDevicesListCalendar': getDevicesListCalendar(); break;
|
|
|
|
case 'updateNetworkLeaf': updateNetworkLeaf(); break;
|
|
case 'overwriteIconType': overwriteIconType(); break;
|
|
case 'getIcons': getIcons(); break;
|
|
case 'getActions': getActions(); break;
|
|
case 'getDevices': getDevices(); break;
|
|
case 'copyFromDevice': copyFromDevice(); break;
|
|
case 'wakeonlan': wakeonlan(); break;
|
|
|
|
default: logServerConsole ('Action: '. $action); break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Query Device Data
|
|
//------------------------------------------------------------------------------
|
|
function getServerDeviceData() {
|
|
global $db;
|
|
|
|
// Request Parameters
|
|
$periodDate = getDateFromPeriod();
|
|
$mac = $_REQUEST['mac'];
|
|
|
|
// Check for "new" MAC case
|
|
if ($mac === "new") {
|
|
$now = date('Y-m-d H:i');
|
|
$deviceData = [
|
|
"devMac" => "",
|
|
"devName" => "",
|
|
"devOwner" => "",
|
|
"devType" => "",
|
|
"devVendor" => "",
|
|
"devFavorite" => 0,
|
|
"devGroup" => "",
|
|
"devComments" => "",
|
|
"devFirstConnection" => $now,
|
|
"devLastConnection" => $now,
|
|
"devLastIP" => "",
|
|
"devStaticIP" => 0,
|
|
"devScan" => 0,
|
|
"devLogEvents" => 0,
|
|
"devAlertEvents" => 0,
|
|
"devAlertDown" => 0,
|
|
"devSkipRepeated" => 0,
|
|
"devLastNotification" => "",
|
|
"devPresentLastScan" => 0,
|
|
"devIsNew" => 1,
|
|
"devLocation" => "",
|
|
"devIsArchived" => 0,
|
|
"devParentMAC" => "",
|
|
"devParentPort" => "",
|
|
"devIcon" => "",
|
|
"devGUID" => "",
|
|
"devSite" => "",
|
|
"devSSID" => "",
|
|
"devSyncHubNode" => "",
|
|
"devSourcePlugin" => "",
|
|
"devCustomProps" => "",
|
|
"devStatus" => "Unknown",
|
|
"devIsRandomMAC" => false,
|
|
"devSessions" => 0,
|
|
"devEvents" => 0,
|
|
"devDownAlerts" => 0,
|
|
"devPresenceHours" => 0
|
|
];
|
|
echo json_encode($deviceData);
|
|
return;
|
|
}
|
|
|
|
|
|
// Device Data
|
|
$sql = 'SELECT rowid, *,
|
|
CASE WHEN devAlertDown !=0 AND devPresentLastScan=0 THEN "Down"
|
|
WHEN devPresentLastScan=1 THEN "On-line"
|
|
ELSE "Off-line" END as devStatus
|
|
FROM Devices
|
|
WHERE devMac="'. $mac .'" or cast(rowid as text)="'. $mac. '"';
|
|
$result = $db->query($sql);
|
|
$row = $result -> fetchArray (SQLITE3_ASSOC);
|
|
$deviceData = $row;
|
|
$mac = $deviceData['devMac'];
|
|
|
|
$deviceData['devParentMAC'] = $row['devParentMAC'];
|
|
$deviceData['devParentPort'] = $row['devParentPort'];
|
|
$deviceData['devFirstConnection'] = formatDate ($row['devFirstConnection']); // Date formated
|
|
$deviceData['devLastConnection'] = formatDate ($row['devLastConnection']); // Date formated
|
|
|
|
$deviceData['devIsRandomMAC'] = isRandomMAC($mac);
|
|
|
|
// Count Totals
|
|
$condition = ' WHERE eve_MAC="'. $mac .'" AND eve_DateTime >= '. $periodDate;
|
|
|
|
// Connections
|
|
$sql = 'SELECT COUNT(*) FROM Sessions
|
|
WHERE ses_MAC="'. $mac .'"
|
|
AND ( ses_DateTimeConnection >= '. $periodDate .'
|
|
OR ses_DateTimeDisconnection >= '. $periodDate .'
|
|
OR ses_StillConnected = 1 )';
|
|
$result = $db->query($sql);
|
|
$row = $result -> fetchArray (SQLITE3_NUM);
|
|
$deviceData['devSessions'] = $row[0];
|
|
|
|
// Events
|
|
$sql = 'SELECT COUNT(*) FROM Events '. $condition .' AND eve_EventType <> "Connected" AND eve_EventType <> "Disconnected" ';
|
|
$result = $db->query($sql);
|
|
$row = $result -> fetchArray (SQLITE3_NUM);
|
|
$deviceData['devEvents'] = $row[0];
|
|
|
|
// Down Alerts
|
|
$sql = 'SELECT COUNT(*) FROM Events '. $condition .' AND eve_EventType = "Device Down"';
|
|
$result = $db->query($sql);
|
|
$row = $result -> fetchArray (SQLITE3_NUM);
|
|
$deviceData['devDownAlerts'] = $row[0];
|
|
|
|
// Get current date using php, sql datetime does not return time respective to timezone.
|
|
$currentdate = date("Y-m-d H:i:s");
|
|
// Presence hours
|
|
$sql = 'SELECT CAST(( MAX (0, SUM (julianday (IFNULL (ses_DateTimeDisconnection,"'. $currentdate .'" ))
|
|
- julianday (CASE WHEN ses_DateTimeConnection < '. $periodDate .' THEN '. $periodDate .'
|
|
ELSE ses_DateTimeConnection END)) *24 )) AS INT)
|
|
FROM Sessions
|
|
WHERE ses_MAC="'. $mac .'"
|
|
AND ses_DateTimeConnection IS NOT NULL
|
|
AND (ses_DateTimeDisconnection IS NOT NULL OR ses_StillConnected = 1 )
|
|
AND ( ses_DateTimeConnection >= '. $periodDate .'
|
|
OR ses_DateTimeDisconnection >= '. $periodDate .'
|
|
OR ses_StillConnected = 1 )';
|
|
$result = $db->query($sql);
|
|
$row = $result -> fetchArray (SQLITE3_NUM);
|
|
$deviceData['devPresenceHours'] = round ($row[0]);
|
|
|
|
// Return json
|
|
echo (json_encode ($deviceData));
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Update Device Data
|
|
//------------------------------------------------------------------------------
|
|
function setDeviceData() {
|
|
global $db;
|
|
|
|
// Sanitize input
|
|
$mac = quotes($_POST['mac']);
|
|
$name = urldecode(quotes($_POST['name']));
|
|
$owner = urldecode(quotes($_POST['owner']));
|
|
$type = urldecode(quotes($_POST['type']));
|
|
$vendor = urldecode(quotes($_POST['vendor']));
|
|
$icon = urldecode(quotes($_POST['icon']));
|
|
$favorite = quotes($_POST['favorite']);
|
|
$group = urldecode(quotes($_POST['group']));
|
|
$location = urldecode(quotes($_POST['location']));
|
|
$comments = urldecode(quotes($_POST['comments']));
|
|
$parentMac = quotes($_POST['networknode']);
|
|
$parentPort = quotes($_POST['networknodeport']);
|
|
$ssid = urldecode(quotes($_POST['ssid']));
|
|
$site = quotes($_POST['networksite']);
|
|
$staticIP = quotes($_POST['staticIP']);
|
|
$scancycle = quotes($_POST['scancycle']);
|
|
$alertevents = quotes($_POST['alertevents']);
|
|
$alertdown = quotes($_POST['alertdown']);
|
|
$skiprepeated = quotes($_POST['skiprepeated']);
|
|
$newdevice = quotes($_POST['newdevice']);
|
|
$archived = quotes($_POST['archived']);
|
|
$devFirstConnection = quotes($_POST['devFirstConnection']);
|
|
$devLastConnection = quotes($_POST['devLastConnection']);
|
|
$ip = quotes($_POST['ip']);
|
|
$devCustomProps = quotes($_POST['devCustomProps']);
|
|
$createNew = quotes($_POST['createNew']);
|
|
$devNewGuid = generateGUID();
|
|
|
|
// An update
|
|
if ($_POST['createNew'] == 0) {
|
|
// UPDATE SQL query
|
|
$sql = "UPDATE Devices SET
|
|
devName = '$name',
|
|
devOwner = '$owner',
|
|
devType = '$type',
|
|
devVendor = '$vendor',
|
|
devIcon = '$icon',
|
|
devFavorite = '$favorite',
|
|
devGroup = '$group',
|
|
devLocation = '$location',
|
|
devComments = '$comments',
|
|
devParentMAC = '$parentMac',
|
|
devParentPort = '$parentPort',
|
|
devSSID = '$ssid',
|
|
devSite = '$site',
|
|
devStaticIP = '$staticIP',
|
|
devScan = '$scancycle',
|
|
devAlertEvents = '$alertevents',
|
|
devAlertDown = '$alertdown',
|
|
devSkipRepeated = '$skiprepeated',
|
|
devIsNew = '$newdevice',
|
|
devIsArchived = '$archived',
|
|
devCustomProps = '$devCustomProps'
|
|
WHERE devMac = '$mac'";
|
|
} else { // An INSERT
|
|
$sql = "INSERT INTO Devices (
|
|
devMac,
|
|
devName,
|
|
devOwner,
|
|
devType,
|
|
devVendor,
|
|
devIcon,
|
|
devFavorite,
|
|
devGroup,
|
|
devLocation,
|
|
devComments,
|
|
devParentMAC,
|
|
devParentPort,
|
|
devSSID,
|
|
devSite,
|
|
devStaticIP,
|
|
devScan,
|
|
devAlertEvents,
|
|
devAlertDown,
|
|
devSkipRepeated,
|
|
devIsNew,
|
|
devIsArchived,
|
|
devLastConnection,
|
|
devFirstConnection,
|
|
devLastIP,
|
|
devGUID,
|
|
devCustomProps
|
|
) VALUES (
|
|
'$mac',
|
|
'$name',
|
|
'$owner',
|
|
'$type',
|
|
'$vendor',
|
|
'$icon',
|
|
'$favorite',
|
|
'$group',
|
|
'$location',
|
|
'$comments',
|
|
'$parentMac',
|
|
'$parentPort',
|
|
'$ssid',
|
|
'$site',
|
|
'$staticIP',
|
|
'$scancycle',
|
|
'$alertevents',
|
|
'$alertdown',
|
|
'$skiprepeated',
|
|
'$newdevice',
|
|
'$archived',
|
|
'$devLastConnection',
|
|
'$devFirstConnection',
|
|
'$ip',
|
|
'$devNewGuid',
|
|
'$devCustomProps'
|
|
)";
|
|
}
|
|
|
|
// Execute the query
|
|
$result = $db->query($sql);
|
|
|
|
// Check the result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_UpdDev');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_UpdDevError')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete Device
|
|
//------------------------------------------------------------------------------
|
|
function deleteDevice() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = 'DELETE FROM Devices WHERE devMac="' . $_REQUEST['mac'] .'"';
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelDev_a');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelDevError_a')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete all devices with empty MAC addresses
|
|
//------------------------------------------------------------------------------
|
|
function deleteAllWithEmptyMACs() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = 'DELETE FROM Devices WHERE devMac=""';
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelDev_b');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelDevError_b')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete all devices with empty MAC addresses
|
|
//------------------------------------------------------------------------------
|
|
function deleteUnknownDevices() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = 'DELETE FROM Devices WHERE devName="(unknown)" OR devName="(name not found)"';
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelDev_b');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelDevError_b')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete Device Events
|
|
//------------------------------------------------------------------------------
|
|
function deleteDeviceEvents() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = 'DELETE FROM Events WHERE eve_MAC="' . $_REQUEST['mac'] .'"';
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelEvents');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelEventsError')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete Device Properties
|
|
//------------------------------------------------------------------------------
|
|
function resetDeviceProps() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = 'UPDATE Devices set devCustomProps = "'.getSettingValue("NEWDEV_devCustomProps").'" WHERE devMac="' . $_REQUEST['mac'] .'"';
|
|
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('Gen_Okay');
|
|
} else {
|
|
echo lang('Gen_Error')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete all devices
|
|
//------------------------------------------------------------------------------
|
|
function deleteAllDevices() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = 'DELETE FROM Devices';
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelDev_b');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelDevError_b')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete all Events
|
|
//------------------------------------------------------------------------------
|
|
function deleteEvents() {
|
|
global $db;
|
|
// sql
|
|
$sql = 'DELETE FROM Events';
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelEvents');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelEventsError')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete all Events older than 30 days
|
|
//------------------------------------------------------------------------------
|
|
function deleteEvents30() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = "DELETE FROM Events WHERE eve_DateTime <= date('now', '-30 day')";
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelEvents');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelEventsError')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Delete History
|
|
//------------------------------------------------------------------------------
|
|
function deleteActHistory() {
|
|
global $db;
|
|
|
|
// sql
|
|
$sql = 'DELETE FROM Online_History';
|
|
// execute sql
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo lang('BackDevices_DBTools_DelActHistory');
|
|
} else {
|
|
echo lang('BackDevices_DBTools_DelActHistoryError')."\n\n$sql \n\n". $db->lastErrorMsg();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Backup DB to Archiv
|
|
//------------------------------------------------------------------------------
|
|
function PiaBackupDBtoArchive() {
|
|
// prepare fast Backup
|
|
$dbfilename = 'app.db';
|
|
$file = '../../../db/'.$dbfilename;
|
|
$newfile = '../../../db/'.$dbfilename.'.latestbackup';
|
|
|
|
// copy files as a fast Backup
|
|
if (!copy($file, $newfile)) {
|
|
echo lang('BackDevices_Backup_CopError');
|
|
} else {
|
|
// Create archive with actual date
|
|
$Pia_Archive_Name = 'appdb_'.date("Ymd_His").'.zip';
|
|
$Pia_Archive_Path = '../../../db/';
|
|
exec('zip -j '.$Pia_Archive_Path.$Pia_Archive_Name.' ../../../db/'.$dbfilename, $output);
|
|
// chheck if archive exists
|
|
if (file_exists($Pia_Archive_Path.$Pia_Archive_Name) && filesize($Pia_Archive_Path.$Pia_Archive_Name) > 0) {
|
|
echo lang('BackDevices_Backup_okay').': ('.$Pia_Archive_Name.')';
|
|
unlink($newfile);
|
|
echo("<meta http-equiv='refresh' content='1'>");
|
|
} else {
|
|
echo lang('BackDevices_Backup_Failed').' ('.$dbfilename.'.latestbackup)';
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Restore DB from Archiv
|
|
//------------------------------------------------------------------------------
|
|
function PiaRestoreDBfromArchive() {
|
|
// prepare fast Backup
|
|
$file = '../../../db/'.$dbfilename;
|
|
$oldfile = '../../../db/'.$dbfilename.'.prerestore';
|
|
|
|
// copy files as a fast Backup
|
|
if (!copy($file, $oldfile)) {
|
|
echo lang('BackDevices_Restore_CopError');
|
|
} else {
|
|
// extract latest archive and overwrite the actual .db
|
|
$Pia_Archive_Path = '../../../db/';
|
|
exec('/bin/ls -Art '.$Pia_Archive_Path.'*.zip | /bin/tail -n 1 | /usr/bin/xargs -n1 /bin/unzip -o -d ../../../db/', $output);
|
|
// check if the .db exists
|
|
if (file_exists($file)) {
|
|
echo lang('BackDevices_Restore_okay');
|
|
unlink($oldfile);
|
|
echo("<meta http-equiv='refresh' content='1'>");
|
|
} else {
|
|
echo lang('BackDevices_Restore_Failed');
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purge Backups
|
|
//------------------------------------------------------------------------------
|
|
function PiaPurgeDBBackups() {
|
|
|
|
$Pia_Archive_Path = '../../../db';
|
|
$Pia_Backupfiles = array();
|
|
$files = array_diff(scandir($Pia_Archive_Path, SCANDIR_SORT_DESCENDING), array('.', '..', $dbfilename, 'netalertxdb-reset.zip'));
|
|
|
|
foreach ($files as &$item)
|
|
{
|
|
$item = $Pia_Archive_Path.'/'.$item;
|
|
if (stristr($item, 'setting_') == '') {array_push($Pia_Backupfiles, $item);}
|
|
}
|
|
|
|
if (sizeof($Pia_Backupfiles) > 3)
|
|
{
|
|
rsort($Pia_Backupfiles);
|
|
unset($Pia_Backupfiles[0], $Pia_Backupfiles[1], $Pia_Backupfiles[2]);
|
|
$Pia_Backupfiles_Purge = array_values($Pia_Backupfiles);
|
|
for ($i = 0; $i < sizeof($Pia_Backupfiles_Purge); $i++)
|
|
{
|
|
unlink($Pia_Backupfiles_Purge[$i]);
|
|
}
|
|
}
|
|
echo lang('BackDevices_DBTools_Purge');
|
|
echo("<meta http-equiv='refresh' content='1'>");
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Export CSV of devices
|
|
//------------------------------------------------------------------------------
|
|
function ExportCSV() {
|
|
|
|
header("Content-Type: application/octet-stream");
|
|
header("Content-Transfer-Encoding: Binary");
|
|
header("Content-disposition: attachment; filename=\"devices.csv\"");
|
|
|
|
global $db;
|
|
$func_result = $db->query("SELECT * FROM Devices");
|
|
|
|
// prepare CSV header row
|
|
$columns = getDevicesColumns();
|
|
|
|
// wrap the headers with " (quotes)
|
|
$resultCSV = '"'.implode('","', $columns).'"'."\n";
|
|
|
|
// retrieve the devices from the DB
|
|
while ($row = $func_result->fetchArray(SQLITE3_ASSOC)) {
|
|
|
|
// loop through columns and add values to the string
|
|
$index = 0;
|
|
foreach ($columns as $columnName) {
|
|
// Escape special chars (e.g.quotes) inside fields by replacing them with html definitions
|
|
$fieldValue = encodeSpecialChars($row[$columnName]);
|
|
|
|
// add quotes around the value to prevent issues with commas in fields
|
|
$resultCSV .= '"'.$fieldValue.'"';
|
|
|
|
// detect last loop - skip as no comma needed
|
|
if ($index != count($columns) - 1) {
|
|
$resultCSV .= ',';
|
|
}
|
|
$index++;
|
|
}
|
|
|
|
// add a new line for the next row
|
|
$resultCSV .= "\n";
|
|
}
|
|
|
|
//write the built CSV string
|
|
echo $resultCSV;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Import CSV of devices
|
|
//------------------------------------------------------------------------------
|
|
function ImportCSV() {
|
|
|
|
global $db;
|
|
$file = '../../../config/devices.csv';
|
|
$data = "";
|
|
$skipped = "";
|
|
$error = "";
|
|
|
|
// check if content passed in query string
|
|
if(isset ($_POST['content']) && !empty ($_POST['content']))
|
|
{
|
|
// Decode the Base64 string
|
|
// $data = base64_decode($_POST['content']);
|
|
$data = base64_decode($_POST['content'], true); // The second parameter ensures safe decoding
|
|
|
|
// // Ensure the decoded data is treated as UTF-8 text
|
|
// $data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
|
|
|
|
} else if (file_exists($file)) { // try to get the data form the file
|
|
|
|
// Read the CSV file
|
|
$data = file_get_contents($file);
|
|
} else {
|
|
echo lang('BackDevices_DBTools_ImportCSVMissing');
|
|
}
|
|
|
|
if($data != "")
|
|
{
|
|
// data cleanup - new lines breaking the CSV
|
|
$data = preg_replace_callback('/"([^"]*)"/', function($matches) {
|
|
// Replace all \n within the quotes with a space
|
|
return str_replace("\n", " ", $matches[0]); // Replace with a space
|
|
}, $data);
|
|
|
|
$lines = explode("\n", $data);
|
|
|
|
// Get the column headers from the first line of the CSV
|
|
$header = str_getcsv(array_shift($lines));
|
|
$header = array_map('trim', $header);
|
|
|
|
// Delete everything form the DB table
|
|
$sql = 'DELETE FROM Devices';
|
|
$result = $db->query($sql);
|
|
|
|
// Build the SQL statement
|
|
$sql = "INSERT INTO Devices (" . implode(', ', $header) . ") VALUES ";
|
|
|
|
// Parse data from CSV file line by line (max 10000 lines)
|
|
$index = 0;
|
|
foreach($lines as $row) {
|
|
$rowArray = str_getcsv($row);
|
|
|
|
if (count($rowArray) === count($header)) {
|
|
// Make sure the number of columns matches the header
|
|
$rowArray = array_map(function ($value) {
|
|
return "'" . SQLite3::escapeString(trim($value)) . "'";
|
|
}, $rowArray);
|
|
|
|
$sql .= "(" . implode(', ', $rowArray) . "), ";
|
|
} else {
|
|
$skipped .= ($index + 1) . ",";
|
|
}
|
|
|
|
$index++;
|
|
}
|
|
|
|
// Remove the trailing comma and space from SQL
|
|
$sql = rtrim($sql, ', ');
|
|
|
|
// Execute the SQL query
|
|
$result = $db->query($sql);
|
|
|
|
if($error === "") {
|
|
// Import successful
|
|
echo lang('BackDevices_DBTools_ImportCSV') . " (Skipped lines: " . $skipped . ") ";
|
|
} else {
|
|
// An error occurred while writing to the DB, display the last error message
|
|
echo lang('BackDevices_DBTools_ImportCSVError') . "\n" . $error . "\n" . $sql . "\n\n" . $result;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Query total numbers of Devices by status
|
|
//------------------------------------------------------------------------------
|
|
function getDevicesTotals() {
|
|
|
|
$resultJSON = "";
|
|
|
|
if(getCache("getDevicesTotals") != "")
|
|
{
|
|
$resultJSON = getCache("getDevicesTotals");
|
|
} else
|
|
{
|
|
global $db;
|
|
|
|
// combined query
|
|
$result = $db->query(
|
|
'SELECT
|
|
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('my').') as devices,
|
|
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('connected').') as connected,
|
|
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('favorites').') as favorites,
|
|
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('new').') as new,
|
|
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('down').') as down,
|
|
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('archived').') as archived
|
|
');
|
|
|
|
$row = $result -> fetchArray (SQLITE3_NUM);
|
|
$resultJSON = json_encode (array ($row[0], $row[1], $row[2], $row[3], $row[4], $row[5]));
|
|
|
|
// save to cache
|
|
setCache("getDevicesTotals", $resultJSON );
|
|
}
|
|
|
|
echo ($resultJSON);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Query the List of devices in a determined Status
|
|
//------------------------------------------------------------------------------
|
|
function getDevicesList() {
|
|
global $db;
|
|
|
|
$forceDefaultOrder = FALSE;
|
|
|
|
if (isset ($_REQUEST['forceDefaultOrder']) )
|
|
{
|
|
$forceDefaultOrder = TRUE;
|
|
}
|
|
|
|
// This object is used to map from the old order ( second parameter, first number) to the new mapping, that is represented by the 3rd parameter (Second number)
|
|
$columnOrderMapping = array(
|
|
array("devName", 0, 0),
|
|
array("devOwner", 1, 1),
|
|
array("devType", 2, 2),
|
|
array("devIcon", 3, 3),
|
|
array("devFavorite", 4, 4),
|
|
array("devGroup", 5, 5),
|
|
array("devFirstConnection", 6, 6),
|
|
array("devLastConnection", 7, 7),
|
|
array("devLastIP", 8, 8),
|
|
array("devMac", 9, 9),
|
|
array("devStatus", 10, 10),
|
|
array("devMac_full", 11, 11),
|
|
array("devLastIP_orderable", 12, 12),
|
|
array("rowid", 13, 13),
|
|
array("devParentMAC", 14, 14),
|
|
array("connected_devices", 15, 15),
|
|
array("devLocation", 16, 16),
|
|
array("devVendor", 17, 17),
|
|
array("devParentPort", 18, 18),
|
|
array("devGUID", 19, 19),
|
|
array("devSyncHubNode", 20, 20),
|
|
array("devSite", 21, 21),
|
|
array("devSSID", 22, 22),
|
|
array("devSourcePlugin", 23, 23)
|
|
);
|
|
|
|
if($forceDefaultOrder == FALSE)
|
|
{
|
|
// get device columns order
|
|
$sql = 'SELECT par_Value FROM Parameters where par_ID = "Front_Devices_Columns_Order"';
|
|
$result = $db->query($sql);
|
|
$row = $result -> fetchArray (SQLITE3_NUM);
|
|
|
|
if($row != NULL && count($row) == 1)
|
|
{
|
|
// ordered columns setting from the maintenance page
|
|
$orderedColumns = createArray($row[0]);
|
|
|
|
// init ordered columns
|
|
for($i = 0; $i < count($orderedColumns); $i++) {
|
|
|
|
$columnOrderMapping[$i][2] = $orderedColumns[$i];
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// SQL
|
|
$condition = getDeviceCondition ($_REQUEST['status']);
|
|
|
|
$sql = 'SELECT * FROM (
|
|
SELECT rowid, *, CASE
|
|
WHEN t1.devAlertDown !=0 AND t1.devPresentLastScan=0 THEN "Down"
|
|
WHEN t1.devIsNew=1 THEN "New"
|
|
WHEN t1.devPresentLastScan=1 THEN "On-line"
|
|
ELSE "Off-line" END AS devStatus
|
|
FROM Devices t1 '.$condition.') t3
|
|
LEFT JOIN
|
|
(
|
|
SELECT devParentMAC as devParentMAC_t2, devMac as devMac_t2,
|
|
count() as connected_devices
|
|
FROM Devices b
|
|
WHERE b.devParentMAC NOT NULL group by b.devParentMAC
|
|
) t2
|
|
ON (t3.devMac = t2.devParentMAC_t2);';
|
|
|
|
$result = $db->query($sql);
|
|
|
|
// arrays of rows
|
|
$tableData = array();
|
|
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
|
|
|
$defaultOrder = array (
|
|
$row['devName'],
|
|
$row['devOwner'],
|
|
handleNull($row['devType']),
|
|
handleNull($row['devIcon'], "PGkgY2xhc3M9J2ZhIGZhLWxhcHRvcCc+PC9pPg=="), // laptop icon
|
|
$row['devFavorite'],
|
|
$row['devGroup'],
|
|
// ----
|
|
formatDate ($row['devFirstConnection']),
|
|
formatDate ($row['devLastConnection']),
|
|
$row['devLastIP'],
|
|
( isRandomMAC($row['devMac']) ),
|
|
$row['devStatus'],
|
|
$row['devMac'], // MAC (hidden)
|
|
formatIPlong ($row['devLastIP']), // IP orderable
|
|
$row['rowid'], // Rowid (hidden)
|
|
handleNull($row['devParentMAC']),
|
|
handleNull($row['connected_devices']),
|
|
handleNull($row['devLocation']),
|
|
handleNull($row['devVendor']),
|
|
handleNull($row['devParentPort']),
|
|
handleNull($row['devGUID']),
|
|
handleNull($row['devSyncHubNode']),
|
|
handleNull($row['devSite']),
|
|
handleNull($row['devSSID']),
|
|
handleNull($row['devSourcePlugin'])
|
|
);
|
|
|
|
$newOrder = array();
|
|
|
|
// reorder columns based on user settings
|
|
for($index = 0; $index < count($columnOrderMapping); $index++)
|
|
{
|
|
array_push($newOrder, $defaultOrder[$columnOrderMapping[$index][2]]);
|
|
}
|
|
|
|
$tableData['data'][] = $newOrder;
|
|
}
|
|
|
|
// Control no rows
|
|
if (empty($tableData['data'])) {
|
|
$tableData['data'] = '';
|
|
}
|
|
|
|
// Return json
|
|
echo (json_encode ($tableData));
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Determine if Random MAC
|
|
//------------------------------------------------------------------------------
|
|
|
|
function isRandomMAC($mac) {
|
|
$isRandom = false;
|
|
|
|
// if detected as random, make sure it doesn't start with a prefix which teh suer doesn't want to mark as random
|
|
$setting = getSettingValue("UI_NOT_RANDOM_MAC");
|
|
$prefixes = createArray($setting);
|
|
|
|
$isRandom = in_array($mac[1], array("2", "6", "A", "E", "a", "e"));
|
|
|
|
// If detected as random, make sure it doesn't start with a prefix which the user doesn't want to mark as random
|
|
if ($isRandom) {
|
|
foreach ($prefixes as $prefix) {
|
|
if (strpos($mac, $prefix) === 0) {
|
|
$isRandom = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $isRandom;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Query the List of devices for calendar
|
|
//------------------------------------------------------------------------------
|
|
function getDevicesListCalendar() {
|
|
global $db;
|
|
|
|
// SQL
|
|
$condition = getDeviceCondition ($_REQUEST['status']);
|
|
$result = $db->query('SELECT * FROM Devices ' . $condition);
|
|
|
|
// arrays of rows
|
|
$tableData = array();
|
|
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
|
if ($row['devFavorite'] == 1) {
|
|
$row['devName'] = '<span class="text-yellow">★</span> '. $row['devName'];
|
|
}
|
|
|
|
$tableData[] = array ('id' => $row['devMac'],
|
|
'title' => $row['devName'],
|
|
'favorite' => $row['devFavorite']);
|
|
}
|
|
|
|
// Return json
|
|
echo (json_encode ($tableData));
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Query Device Data
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
function getIcons() {
|
|
global $db;
|
|
|
|
// Device Data
|
|
$sql = 'select devIcon from Devices group by devIcon';
|
|
|
|
$result = $db->query($sql);
|
|
|
|
// arrays of rows
|
|
$tableData = array();
|
|
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
|
$icon = handleNull($row['devIcon'], "<i class='fa fa-laptop'></i>");
|
|
// Push row data
|
|
$tableData[] = array('id' => $icon,
|
|
'name' => $icon );
|
|
}
|
|
|
|
// Control no rows
|
|
if (empty($tableData)) {
|
|
$tableData = [];
|
|
}
|
|
|
|
// Return json
|
|
echo (json_encode ($tableData));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
function getActions() {
|
|
|
|
$tableData = array(
|
|
array('id' => 'wake-on-lan',
|
|
'name' => lang('DevDetail_WOL_Title'))
|
|
);
|
|
|
|
// Return json
|
|
echo (json_encode ($tableData));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
function getDevices() {
|
|
|
|
global $db;
|
|
|
|
// Device Data
|
|
$sql = 'select devMac, devName from Devices';
|
|
|
|
$result = $db->query($sql);
|
|
|
|
// arrays of rows
|
|
$tableData = array();
|
|
|
|
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
|
$name = handleNull($row['devName'], "(unknown)");
|
|
$mac = handleNull($row['devMac'], "(unknown)");
|
|
// Push row data
|
|
$tableData[] = array('id' => $mac,
|
|
'name' => $name );
|
|
}
|
|
|
|
// Control no rows
|
|
if (empty($tableData)) {
|
|
$tableData = [];
|
|
}
|
|
|
|
// Return json
|
|
echo (json_encode ($tableData));
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
function updateNetworkLeaf()
|
|
{
|
|
$nodeMac = $_REQUEST['value']; // parent
|
|
$leafMac = $_REQUEST['id']; // child
|
|
|
|
if ((false === filter_var($nodeMac , FILTER_VALIDATE_MAC) && $nodeMac != "Internet" && $nodeMac != "") || false === filter_var($leafMac , FILTER_VALIDATE_MAC) ) {
|
|
throw new Exception('Invalid mac address');
|
|
}
|
|
else
|
|
{
|
|
global $db;
|
|
// sql
|
|
$sql = 'UPDATE Devices SET "devParentMAC" = "'. $nodeMac .'" WHERE "devMac"="' . $leafMac.'"' ;
|
|
// update Data
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo 'OK';
|
|
} else {
|
|
echo 'KO';
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
function overwriteIconType()
|
|
{
|
|
$mac = $_REQUEST['mac'];
|
|
$icon = $_REQUEST['icon'];
|
|
|
|
if ((false === filter_var($mac , FILTER_VALIDATE_MAC) && $mac != "Internet" && $mac != "") ) {
|
|
throw new Exception('Invalid mac address');
|
|
}
|
|
else
|
|
{
|
|
global $db;
|
|
// sql
|
|
$sql = 'UPDATE Devices SET "devIcon" = "'. $icon .'" where devType in (select devType from Devices where devMac = "' . $mac.'")' ;
|
|
// update Data
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo 'OK';
|
|
} else {
|
|
echo lang('BackDevices_Device_UpdDevError');
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Wake-on-LAN
|
|
// Inspired by @leiweibau: https://github.com/leiweibau/Pi.Alert/commit/30427c7fea180670c71a2b790699e5d9e9e88ffd
|
|
//------------------------------------------------------------------------------
|
|
function wakeonlan() {
|
|
|
|
$WOL_HOST_IP = $_REQUEST['ip'];
|
|
$WOL_HOST_MAC = $_REQUEST['mac'];
|
|
|
|
if (!filter_var($WOL_HOST_IP, FILTER_VALIDATE_IP)) {
|
|
echo "Invalid IP! ". lang('BackDevDetail_Tools_WOL_error'); exit;
|
|
}
|
|
elseif (!filter_var($WOL_HOST_MAC, FILTER_VALIDATE_MAC)) {
|
|
echo "Invalid MAC! ". lang('BackDevDetail_Tools_WOL_error'); exit;
|
|
}
|
|
|
|
exec('wakeonlan '.$WOL_HOST_MAC , $output);
|
|
|
|
echo lang('BackDevDetail_Tools_WOL_okay');
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Copy from device
|
|
//------------------------------------------------------------------------------
|
|
function copyFromDevice() {
|
|
|
|
$MAC_FROM = $_REQUEST['macFrom'];
|
|
$MAC_TO = $_REQUEST['macTo'];
|
|
|
|
global $db;
|
|
|
|
// clean-up temporary table
|
|
$sql = "DROP TABLE IF EXISTS temp_devices ";
|
|
$result = $db->query($sql);
|
|
|
|
// create temporary table with the source data
|
|
$sql = "CREATE TABLE temp_devices AS SELECT * FROM Devices WHERE devMac = '". $MAC_FROM . "';";
|
|
$result = $db->query($sql);
|
|
|
|
// update temporary table with the correct target MAC
|
|
$sql = "UPDATE temp_devices SET devMac = '". $MAC_TO . "';";
|
|
$result = $db->query($sql);
|
|
|
|
// delete previous entry
|
|
$sql = "DELETE FROM Devices WHERE devMac = '". $MAC_TO . "';";
|
|
$result = $db->query($sql);
|
|
|
|
// insert new entry with the correct target MAC from the temporary table
|
|
$sql = "INSERT INTO Devices SELECT * FROM temp_devices WHERE devMac = '".$MAC_TO."'";
|
|
$result = $db->query($sql);
|
|
|
|
// clean-up temporary table
|
|
$sql = "DROP TABLE temp_devices ";
|
|
$result = $db->query($sql);
|
|
|
|
// check result
|
|
if ($result == TRUE) {
|
|
echo 'OK';
|
|
} else {
|
|
echo lang('BackDevices_Device_UpdDevError');
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Status Where conditions
|
|
//------------------------------------------------------------------------------
|
|
function getDeviceCondition ($deviceStatus) {
|
|
switch ($deviceStatus) {
|
|
case 'all': return 'WHERE devIsArchived=0'; break;
|
|
case 'my': return 'WHERE devIsArchived=0'; break;
|
|
case 'connected': return 'WHERE devIsArchived=0 AND devPresentLastScan=1'; break;
|
|
case 'favorites': return 'WHERE devIsArchived=0 AND devFavorite=1'; break;
|
|
case 'new': return 'WHERE devIsArchived=0 AND devIsNew=1'; break;
|
|
case 'down': return 'WHERE devIsArchived=0 AND devAlertDown !=0 AND devPresentLastScan=0'; break;
|
|
case 'archived': return 'WHERE devIsArchived=1'; break;
|
|
default: return 'WHERE 1=0'; break;
|
|
}
|
|
}
|
|
|
|
|
|
?>
|