10000) { $lines = array_slice($lines, 0, 10000); } $final = implode("\n", $lines); if (!file_put_contents($logFile, $final, LOCK_EX)) { file_put_contents("/tmp/fallback.log", $line, FILE_APPEND); } } // ============================ // START LOG // ============================ writeLog("🚀 START {$m_ip} - {$nama}"); // ============================ // API // ============================ $API = new RouterosAPI(); $API->timeout = 3; // ============================ // CONNECT // ============================ if (!$API->connect2($m_ip, $m_user, $m_pass, $m_port)) { writeLog("❌ Gagal konek ke {$m_ip}"); // SUMMARY FAIL file_put_contents($mainLogFile, "[" . date('Y-m-d H:i:s') . "] FAIL | {$m_ip} | {$nama}\n", FILE_APPEND | LOCK_EX ); exit; } writeLog("✅ Connected ke {$m_ip} : Mulai Check Voucher"); // ============================ // HOTSPOT CACHE // ============================ $hotspot = $API->comm('/ip/hotspot/user/print'); $userMap = []; if (is_array($hotspot)) { foreach ($hotspot as $u) { $userMap[$u['name']] = $u; } } // ============================ // LOOP DB // ============================ $batchSize = 200; $offset = 0; do { $stmt = $pdo->prepare(" SELECT id, create_time, voucher, durasi FROM v_load_cek_voucher WHERE id_setting_mikrotik = :idsm LIMIT {$batchSize} OFFSET {$offset} "); $stmt->bindValue(':idsm', $idsm, PDO::PARAM_INT); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!$rows) break; foreach ($rows as $r) { $id = $r['id']; $voucher = $r['voucher']; $durasi = $r['durasi']; $interval = convertDurationToInterval($durasi); if (!$interval) { writeLog("⛔ {$voucher} durasi invalid"); continue; } if (isset($userMap[$voucher])) { $comment = $userMap[$voucher]['comment'] ?? ''; if ($comment) { $activetime = processCommentDate($comment); if (!$activetime) { writeLog("❌ {$voucher} tanggal invalid"); continue; } $tgl = new DateTime($activetime); $tgl->add($interval); $exp = $tgl->format('Y-m-d H:i:s'); updateVoucher($pdo, $id, $activetime, $exp); writeLog("✅ {$voucher} aktif : {$activetime} , exp: {$exp}"); } else { markVoucherChecked($pdo, $id); writeLog("â„šī¸ {$voucher} tanpa comment"); } } else { $aktif = $r['create_time']; $tgl = new DateTime($aktif); $tgl->add($interval); $exp = $tgl->format('Y-m-d H:i:s'); updateVoucher($pdo, $id, $aktif, $exp); writeLog("âš ī¸ {$voucher} tidak ada di Mikrotik, aktif: {$aktif}, exp: {$exp}"); } usleep(50000); } $offset += $batchSize; } while (count($rows) == $batchSize); // ============================ // FINISH // ============================ $API->disconnect(); $end_time = microtime(true); $duration = $end_time - $start_time; $duration_format = gmdate("H:i:s", (int)$duration); // log biasa writeLog("✅ SELESAI {$m_ip} | Durasi: {$duration_format} ({$duration} detik) | Last cek " . date('Y-m-d H:i:s')); // ============================ // đŸ”Ĩ SUMMARY KE MAIN LOG // ============================ $logLine = sprintf( "[%s] OK | %-15s | %-25s | Durasi: %s (%.2f detik)", date('Y-m-d H:i:s'), $m_ip, $nama, $duration_format, $duration ); // baca log lama $oldContent = file_exists($mainLogFile) ? file($mainLogFile, FILE_IGNORE_NEW_LINES) : []; // filter: hapus yang sama (IP + Nama) $newContent = []; foreach ($oldContent as $line) { if (strpos($line, $m_ip) !== false && strpos($line, $nama) !== false) { continue; // skip yang lama } $newContent[] = $line; } // tambahkan yang baru di paling atas array_unshift($newContent, $logLine); // tulis ulang file file_put_contents( $mainLogFile, implode("\n", $newContent) . "\n", LOCK_EX ); // ============================ // HELPER // ============================ function convertDurationToInterval($d) { if (substr($d, -1) == 'H') return new DateInterval("PT" . rtrim($d, 'H') . "H"); if (substr($d, -1) == 'D') return new DateInterval("P" . rtrim($d, 'D') . "D"); if (substr($d, -1) == 'M') return new DateInterval("PT" . rtrim($d, 'M') . "M"); return false; } function processCommentDate($c) { $d = substr($c, 6); if (substr($d, 0, 4) == date('Y')) { return $d; } $date = date_create_from_format("M/d/Y H:i:s", $d); return $date ? date_format($date, "Y-m-d H:i:s") : null; } function updateVoucher($pdo, $id, $a, $e) { $stmt = $pdo->prepare("UPDATE ganerate_voucher SET active_time=?, expaired_time=? WHERE id=?"); $stmt->execute([$a, $e, $id]); } function markVoucherChecked($pdo, $id) { $stmt = $pdo->prepare("UPDATE ganerate_voucher SET status_cek='1' WHERE id=?"); $stmt->execute([$id]); }