251 lines
7.5 KiB
PHP
251 lines
7.5 KiB
PHP
<?php
|
|
$start_time = microtime(true);
|
|
|
|
if (php_sapi_name() !== 'cli') {
|
|
die("Script ini hanya bisa dijalankan lewat CLI.\n");
|
|
}
|
|
|
|
ini_set('max_execution_time', 0);
|
|
date_default_timezone_set('Asia/Jakarta');
|
|
|
|
require "/www/wwwroot/bilspro/config/routeros_api.class.php";
|
|
|
|
// ---------------- Config ----------------
|
|
$max_processes = 10;
|
|
$timeout_api = 3;
|
|
$tmpDir = sys_get_temp_dir() . '/mt_results';
|
|
|
|
if (!is_dir($tmpDir)) {
|
|
@mkdir($tmpDir, 0770, true);
|
|
}
|
|
|
|
// Ambil daftar perangkat
|
|
include "/www/wwwroot/bilspro/config/connect.php";
|
|
$sqlList = "
|
|
SELECT DISTINCT ip_address, port_api, username, password, board_id
|
|
FROM setting_mikrotik";
|
|
$stmt = $pdo->prepare($sqlList);
|
|
$stmt->execute();
|
|
$mikrotiks = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
$pdo = null;
|
|
|
|
if (empty($mikrotiks)) {
|
|
echo "[" . date('Y-m-d H:i:s') . "] Tidak ada data MikroTik.\n";
|
|
exit(0);
|
|
}
|
|
|
|
// Fork parallel
|
|
$child_pids = [];
|
|
$outfiles = [];
|
|
|
|
foreach ($mikrotiks as $data) {
|
|
while (count($child_pids) >= $max_processes) {
|
|
foreach ($child_pids as $key => $pid) {
|
|
if (pcntl_waitpid($pid, $status, WNOHANG) > 0) {
|
|
unset($child_pids[$key]);
|
|
}
|
|
}
|
|
usleep(100000);
|
|
}
|
|
|
|
$safeId = preg_replace('~[^A-Za-z0-9_\-]~', '_', substr($data['board_id'], 0, 64));
|
|
$outfile = $tmpDir . "/mt_" . $safeId . "_" . microtime(true) . "_" . mt_rand(1000,9999) . ".json";
|
|
$outfiles[] = $outfile;
|
|
|
|
$pid = pcntl_fork();
|
|
if ($pid == -1) {
|
|
echo "[" . date('Y-m-d H:i:s') . "] Gagal fork.\n";
|
|
continue;
|
|
} elseif ($pid) {
|
|
$child_pids[] = $pid;
|
|
} else {
|
|
process_mikrotik_child($data, $timeout_api, $outfile);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
foreach ($child_pids as $pid) {
|
|
pcntl_waitpid($pid, $status);
|
|
}
|
|
|
|
echo "[" . date('Y-m-d H:i:s') . "] Semua child selesai. Mulai update DB...\n";
|
|
|
|
// Update DB
|
|
include "/www/wwwroot/bilspro/config/connect.php";
|
|
|
|
$updateSql = "
|
|
UPDATE setting_mikrotik
|
|
SET pppa = :pppa,
|
|
hsa = :hsa,
|
|
uptime = :ut,
|
|
board_name = :bm,
|
|
status = :st
|
|
WHERE board_id = :id
|
|
";
|
|
$statusOnlySql = "
|
|
UPDATE setting_mikrotik
|
|
SET status = :st
|
|
WHERE board_id = :id
|
|
";
|
|
|
|
$updateStmt = $pdo->prepare($updateSql);
|
|
$statusOnlyStmt = $pdo->prepare($statusOnlySql);
|
|
|
|
$execWithRetry = function($stmt, $params) use (&$pdo, $updateSql, $statusOnlySql, &$updateStmt, &$statusOnlyStmt) {
|
|
try {
|
|
$stmt->execute($params);
|
|
return true;
|
|
} catch (PDOException $e) {
|
|
$msg = $e->getMessage();
|
|
if (stripos($msg, '2006 MySQL server has gone away') !== false) {
|
|
$pdo = null;
|
|
include "/www/wwwroot/bilspro/config/connect.php";
|
|
$updateStmt = $pdo->prepare($updateSql);
|
|
$statusOnlyStmt = $pdo->prepare($statusOnlySql);
|
|
$stmt = (isset($params[':pppa']) ? $updateStmt : $statusOnlyStmt);
|
|
$stmt->execute($params);
|
|
return true;
|
|
}
|
|
throw $e;
|
|
}
|
|
};
|
|
|
|
$updated = 0;
|
|
$failed = 0;
|
|
|
|
foreach ($outfiles as $file) {
|
|
if (!is_file($file)) continue;
|
|
|
|
$json = file_get_contents($file);
|
|
@unlink($file);
|
|
|
|
$row = json_decode($json, true);
|
|
if (!$row || !isset($row['board_id'], $row['status'])) {
|
|
$failed++;
|
|
continue;
|
|
}
|
|
|
|
$paramsStatus = [
|
|
':st' => $row['status'],
|
|
':id' => $row['board_id'],
|
|
];
|
|
|
|
// Cek data lama untuk log perbandingan
|
|
$cekStmt = $pdo->prepare("SELECT pppa,hsa,uptime,board_name,status FROM setting_mikrotik WHERE board_id = :id");
|
|
$cekStmt->execute([':id' => $row['board_id']]);
|
|
$current = $cekStmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($row['status'] === 'Connected') {
|
|
$params = [
|
|
':pppa' => $row['pppa'] ?? '',
|
|
':hsa' => $row['hsa'] ?? '',
|
|
':ut' => $row['uptime'] ?? '',
|
|
':bm' => $row['board_name'] ?? '',
|
|
':st' => 'Connected',
|
|
':id' => $row['board_id'],
|
|
];
|
|
try {
|
|
$execWithRetry($updateStmt, $params);
|
|
$updated++;
|
|
|
|
echo "[" . date('H:i:s') . "] [UPDATE DB] {$row['board_id']} \n ";
|
|
// echo "OLD: " . json_encode($current, JSON_UNESCAPED_UNICODE) . "\n NEW: " . json_encode($params, JSON_UNESCAPED_UNICODE) . "\n";
|
|
} catch (PDOException $e) {
|
|
echo "[" . date('H:i:s') . "] [DB ERROR] {$row['board_id']} - " . $e->getMessage() . "\n";
|
|
$failed++;
|
|
}
|
|
} else {
|
|
try {
|
|
$execWithRetry($statusOnlyStmt, $paramsStatus);
|
|
$updated++;
|
|
echo "[" . date('H:i:s') . "] [UPDATE STATUS] {$row['board_id']} ({$current['status']} -> {$row['status']})\n";
|
|
} catch (PDOException $e) {
|
|
echo "[" . date('H:i:s') . "] [DB ERROR] {$row['board_id']} - " . $e->getMessage() . "\n";
|
|
$failed++;
|
|
}
|
|
}
|
|
}
|
|
|
|
$pdo = null;
|
|
echo "[" . date('Y-m-d H:i:s') . "] Update DB selesai. OK: {$updated}, FAIL: {$failed}\n";
|
|
|
|
$end_time = microtime(true);
|
|
$duration = $end_time - $start_time;
|
|
echo "[" . date('Y-m-d H:i:s') . "] Lama eksekusi: " . number_format($duration, 2) . " detik\n";
|
|
|
|
exit(0);
|
|
|
|
// ================================
|
|
// CHILD: konek RouterOS & tulis file hasil
|
|
// ================================
|
|
function process_mikrotik_child(array $data, int $timeout_api, string $outfile): void
|
|
{
|
|
$ip = $data['ip_address'];
|
|
$username = $data['username'];
|
|
$password = $data['password'];
|
|
$port = $data['port_api'];
|
|
$board_id = $data['board_id'];
|
|
|
|
$API = new RouterosAPI();
|
|
$API->debug = false;
|
|
$API->timeout = $timeout_api;
|
|
|
|
$result = [
|
|
'board_id' => $board_id,
|
|
'status' => 'Disconnected',
|
|
'pppa' => '',
|
|
'hsa' => '',
|
|
'board_name' => '',
|
|
'uptime' => '',
|
|
'ip' => $ip,
|
|
];
|
|
|
|
if ($API->connect2($ip, $username, $password, $port)) {
|
|
$pppoe_active = [];
|
|
$pppoe_data = $API->comm("/ppp/active/print");
|
|
if (is_array($pppoe_data)) {
|
|
foreach ($pppoe_data as $item) {
|
|
$name = $item['name'] ?? '';
|
|
$addr = $item['address'] ?? '';
|
|
if ($name !== '' && $addr !== '') {
|
|
$pppoe_active[] = "{$name}_{$addr}";
|
|
}
|
|
}
|
|
}
|
|
|
|
$hotspot_active = [];
|
|
$hotspot_users = $API->comm("/ip/hotspot/user/print");
|
|
if (is_array($hotspot_users)) {
|
|
foreach ($hotspot_users as $item) {
|
|
$user = $item['name'] ?? '';
|
|
$comment = $item['comment'] ?? '';
|
|
if ($user !== '' && strpos($comment, 'Login.') === 0) {
|
|
$hotspot_active[] = "{$user}_" . substr($comment, 6);
|
|
}
|
|
}
|
|
}
|
|
|
|
$sys = $API->comm("/system/resource/print");
|
|
$board_name = '';
|
|
$uptime = '';
|
|
if (is_array($sys) && !empty($sys[0])) {
|
|
$board_name = $sys[0]['board-name'] ?? '';
|
|
$uptime = $sys[0]['uptime'] ?? '';
|
|
}
|
|
|
|
$API->disconnect();
|
|
|
|
$result['status'] = 'Connected';
|
|
$result['pppa'] = implode('|', $pppoe_active);
|
|
$result['hsa'] = implode('|', $hotspot_active);
|
|
$result['board_name'] = $board_name;
|
|
$result['uptime'] = $uptime;
|
|
|
|
echo "[" . date('H:i:s') . "] [OK] {$ip}\n";
|
|
} else {
|
|
echo "[" . date('H:i:s') . "] [FAIL] {$ip}\n";
|
|
}
|
|
|
|
file_put_contents($outfile, json_encode($result, JSON_UNESCAPED_UNICODE));
|
|
}
|