Files
manjapro_v6/load/cronjob/check_mikrotik_list.php
2026-08-20 18:39:37 +07:00

257 lines
7.4 KiB
PHP

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$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";
$sqlList = "
SELECT sm.ip_address, sm.port_api, sm.username, sm.password, sm.board_id
FROM setting_mikrotik sm
WHERE EXISTS (
SELECT 1
FROM data_server ds
WHERE ds.id = sm.id_data_server
AND ds.expaired_date >= CURDATE()
)
";
$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";
$pdo->exec("SET time_zone = '+07:00'");
echo "[" . date('Y-m-d H:i:s') . "] Semua child selesai. Mulai update DB masal...\n";
$updated = 0;
$skipped = 0;
$failed = 0;
try {
$pdo->beginTransaction();
$updateSql = "
UPDATE setting_mikrotik
SET pppa = :pppa,
hsa = :hsa,
uptime = :ut,
board_name = :bm,
status = :st,
last_time = NOW()
WHERE board_id = :id
";
$statusOnlySql = "
UPDATE setting_mikrotik
SET status = :st
WHERE board_id = :id
";
$updateStmt = $pdo->prepare($updateSql);
$statusOnlyStmt = $pdo->prepare($statusOnlySql);
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;
}
if ($row['status'] === 'Connected') {
$params = [
':pppa' => $row['pppa'] ?? '',
':hsa' => $row['hsa'] ?? '',
':ut' => $row['uptime'] ?? '',
':bm' => $row['board_name'] ?? '',
':st' => 'Connected',
':id' => $row['board_id'],
];
$updateStmt->execute($params);
echo "Update count: " . $updateStmt->rowCount() . "\n";
// Cek apakah ada perubahan data asli
if ($updateStmt->rowCount() > 0) {
echo "[" . date('H:i:s') . "] [UPDATE] {$row['board_id']} - Data diperbarui.\n";
$updated++;
} else {
echo "[" . date('H:i:s') . "] [SKIP] {$row['board_id']} - Data masih sama.\n";
$skipped++;
}
} else {
$statusOnlyStmt->execute([
':st' => $row['status'],
':id' => $row['board_id'],
]);
if ($statusOnlyStmt->rowCount() > 0) {
echo "[" . date('H:i:s') . "] [OFFLINE] {$row['board_id']} - Status menjadi {$row['status']}.\n";
$updated++;
} else {
$skipped++;
}
}
}
// Komit semua perubahan sekaligus
$pdo->commit();
echo "[" . date('Y-m-d H:i:s') . "] Transaksi berhasil dicommit ke Database.\n";
} catch (Exception $e) {
// Jika ada error fatal, batalkan semua agar data tidak korup
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
echo "[" . date('Y-m-d H:i:s') . "] [CRITICAL ERROR] " . $e->getMessage() . "\n";
}
$pdo = null;
echo "[" . date('Y-m-d H:i:s') . "] Selesai. OK: {$updated}, SKIP: {$skipped}, FAIL: {$failed}\n";
// ================================
// 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'] ?? '';
$mac = $item['caller-id'] ?? '';
if ($name !== '' && $addr !== '') {
$pppoe_active[] = "{$name}_{$addr}_{$mac}";
}
}
}
$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));
}