259 lines
7.2 KiB
PHP
259 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers;
|
|
use CodeIgniter\Controller;
|
|
use App\Controllers\BaseController;
|
|
|
|
class LogController extends BaseController
|
|
{
|
|
private $logPath;
|
|
public $dModel;
|
|
public $session;
|
|
|
|
public function __construct()
|
|
{
|
|
// Path to log files
|
|
$this->logPath = WRITEPATH . 'logs/';
|
|
$this->session = session();
|
|
}
|
|
|
|
/**
|
|
* Display list of all log files
|
|
*/
|
|
public function index()
|
|
{
|
|
|
|
$logFiles = $this->getLogFiles();
|
|
|
|
$data = [
|
|
'title' => 'Log Files',
|
|
'logFiles' => $logFiles
|
|
];
|
|
|
|
return $this->loadLayout('logs/index', $data);
|
|
|
|
// return view('logs/index', $data);
|
|
}
|
|
|
|
/**
|
|
* Get all log files sorted by date (latest first)
|
|
*/
|
|
private function getLogFiles()
|
|
{
|
|
$files = [];
|
|
|
|
if (!is_dir($this->logPath)) {
|
|
return $files;
|
|
}
|
|
|
|
$iterator = new \DirectoryIterator($this->logPath);
|
|
|
|
foreach ($iterator as $fileInfo) {
|
|
if ($fileInfo->isFile() && $fileInfo->getExtension() === 'log') {
|
|
$files[] = [
|
|
'name' => $fileInfo->getFilename(),
|
|
'path' => $fileInfo->getPathname(),
|
|
'size' => $this->formatBytes($fileInfo->getSize()),
|
|
'modified' => $fileInfo->getMTime(),
|
|
'modified_date' => date('Y-m-d H:i:s', $fileInfo->getMTime())
|
|
];
|
|
}
|
|
}
|
|
|
|
// Sort by modified time (latest first)
|
|
usort($files, function($a, $b) {
|
|
return $b['modified'] - $a['modified'];
|
|
});
|
|
|
|
return $files;
|
|
}
|
|
|
|
/**
|
|
* View specific log file content
|
|
*/
|
|
public function view($filename = null)
|
|
{
|
|
|
|
|
|
|
|
if (!$filename) {
|
|
return redirect()->to('/logs')->with('error', 'No log file specified');
|
|
}
|
|
|
|
// Security: prevent directory traversal
|
|
$filename = basename($filename);
|
|
$filePath = $this->logPath . $filename;
|
|
|
|
if (!file_exists($filePath)) {
|
|
return redirect()->to('/logs')->with('error', 'Log file not found');
|
|
}
|
|
|
|
// ✅ extract date from filename: log-YYYY-MM-DD.log
|
|
if (preg_match('/log-(\d{4}-\d{2}-\d{2})\.log/', $filename, $match)) {
|
|
$currentDate = $match[1];
|
|
|
|
$prevDate = date('Y-m-d', strtotime('-1 day', strtotime($currentDate)));
|
|
$nextDate = date('Y-m-d', strtotime('+1 day', strtotime($currentDate)));
|
|
|
|
$prevFile = "log-$prevDate.log";
|
|
$nextFile = "log-$nextDate.log";
|
|
|
|
$prevExists = file_exists($this->logPath . $prevFile);
|
|
$nextExists = file_exists($this->logPath . $nextFile);
|
|
}
|
|
|
|
// Read log file content
|
|
$content = file_get_contents($filePath);
|
|
$logEntries = $this->parseLogFile($content);
|
|
|
|
$data = [
|
|
'title' => 'View Log: ' . $filename,
|
|
'filename' => $filename,
|
|
'logEntries' => $logEntries,
|
|
'prevFile' => $prevExists ? $prevFile : null,
|
|
'nextFile' => $nextExists ? $nextFile : null,
|
|
'fileSize' => $this->formatBytes(filesize($filePath)),
|
|
'lastModified' => date('Y-m-d H:i:s', filemtime($filePath))
|
|
];
|
|
|
|
// print_r( $data); die;
|
|
|
|
return $this->loadLayout('logs/view', $data);
|
|
// return view('logs/view', $data);
|
|
}
|
|
|
|
/**
|
|
* Parse log file into structured array
|
|
*/
|
|
|
|
private function parseLogFile($content)
|
|
{
|
|
$entries = [];
|
|
$lines = explode("\n", $content);
|
|
|
|
$currentEntry = null;
|
|
|
|
// Messages to filter out
|
|
$skipPatterns = [
|
|
'/Session: Class initialized using/',
|
|
'/Session class already loaded/',
|
|
];
|
|
|
|
foreach ($lines as $line) {
|
|
// Match CI4 log format: LEVEL - date --> message
|
|
if (preg_match('/^(\w+)\s*-\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s*-->\s*(.*)$/', $line, $matches)) {
|
|
|
|
// Save previous entry if exists (before checking skip)
|
|
if ($currentEntry !== null) {
|
|
$entries[] = $currentEntry;
|
|
$currentEntry = null;
|
|
}
|
|
|
|
// Check if this message should be skipped
|
|
$shouldSkip = false;
|
|
foreach ($skipPatterns as $pattern) {
|
|
if (preg_match($pattern, $matches[3])) {
|
|
$shouldSkip = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($shouldSkip) {
|
|
continue;
|
|
}
|
|
|
|
// Start new entry
|
|
$currentEntry = [
|
|
'level' => $matches[1],
|
|
'date' => $matches[2],
|
|
'message' => $matches[3]
|
|
];
|
|
} elseif ($currentEntry !== null && trim($line) !== '') {
|
|
// Continuation of previous message
|
|
$currentEntry['message'] .= "\n" . $line;
|
|
}
|
|
}
|
|
|
|
// Add last entry
|
|
if ($currentEntry !== null) {
|
|
$entries[] = $currentEntry;
|
|
}
|
|
|
|
return array_reverse($entries); // Latest first
|
|
}
|
|
|
|
/**
|
|
* Download log file
|
|
*/
|
|
public function download($filename = null)
|
|
{
|
|
if (!$filename) {
|
|
return redirect()->to('/logs')->with('error', 'No log file specified');
|
|
}
|
|
|
|
$filename = basename($filename);
|
|
$filePath = $this->logPath . $filename;
|
|
|
|
if (!file_exists($filePath)) {
|
|
return redirect()->to('/logs')->with('error', 'Log file not found');
|
|
}
|
|
|
|
return $this->response->download($filePath, null);
|
|
}
|
|
|
|
/**
|
|
* Delete log file
|
|
*/
|
|
public function delete($filename = null)
|
|
{
|
|
if (!$filename) {
|
|
return redirect()->to('/logs')->with('error', 'No log file specified');
|
|
}
|
|
|
|
$filename = basename($filename);
|
|
$filePath = $this->logPath . $filename;
|
|
|
|
if (!file_exists($filePath)) {
|
|
return redirect()->to('/logs')->with('error', 'Log file not found');
|
|
}
|
|
|
|
if (unlink($filePath)) {
|
|
return redirect()->to('/logs')->with('success', 'Log file deleted successfully');
|
|
} else {
|
|
return redirect()->to('/logs')->with('error', 'Failed to delete log file');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format bytes to human readable format
|
|
*/
|
|
private function formatBytes($bytes, $precision = 2)
|
|
{
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
|
|
$bytes = max($bytes, 0);
|
|
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
|
$pow = min($pow, count($units) - 1);
|
|
|
|
$bytes /= pow(1024, $pow);
|
|
|
|
return round($bytes, $precision) . ' ' . $units[$pow];
|
|
}
|
|
|
|
/**
|
|
* Clear all log files
|
|
*/
|
|
public function clearAll()
|
|
{
|
|
$logFiles = $this->getLogFiles();
|
|
$deleted = 0;
|
|
|
|
foreach ($logFiles as $file) {
|
|
if (unlink($file['path'])) {
|
|
$deleted++;
|
|
}
|
|
}
|
|
|
|
return redirect()->to('/logs')->with('success', $deleted . ' log file(s) deleted successfully');
|
|
}
|
|
} |