HEX
Server: LiteSpeed
System: Linux php-prod-1.spaceapp.ru 5.15.0-157-generic #167-Ubuntu SMP Wed Sep 17 21:35:53 UTC 2025 x86_64
User: xnsbb3110 (1041)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: //usr/local/lsws/admin/html/lib/LogViewer.php
<?php

class LogFilter
{

    const LOGTYPE_ERRLOG = 1;
    const LOGTYPE_ACCESS = 2;
    const LOGTYPE_RESTART = 3;

    //'E' => 1, 'W' => 2, 'N' => 3, 'I' => 4, 'D' => 5

    private $LEVEL_DESCR = [1 => 'ERROR', 2 => 'WARNING', 3 => 'NOTICE', 4 => 'INFO', 5 => 'DEBUG'];

    const LEVEL_ERR = 1;
    const LEVEL_WARN = 2;
    const LEVEL_NOTICE = 3;
    const LEVEL_INFO = 4;
    const LEVEL_DEBUG = 5;
    const POS_FILEEND = -1;
    const FLD_LEVEL = 1;
    const FLD_LOGFILE = 2;
    const FLD_FROMINPUT = 3;
    const FLD_BLKSIZE = 4;
    const FLD_FROMPOS = 5;
    const FLD_TOPOS = 6;
    const FLD_TOTALSEARCHED = 7;
    const FLD_OUTMESG = 8;
    const FLD_TOTALFOUND = 9;
    const FLD_FILE_SIZE = 10;

    private $_logfile;
    private $_logtype;
    private $_level;
    private $_frominput;
    private $_blksize;
    private $_frompos;
    private $_topos;
    private $_filesize;
    private $_output = '';
    private $_outlines = 0;
    private $_totallines = 0;
    private $_outmesg = '';

    public function __construct($filename, $type = self::LOGTYPE_ERRLOG)
    {
        $this->_logfile = $filename;
        $this->_logtype = $type;
    }

    public function Get($field)
    {
        switch ($field) {
            case self::FLD_LEVEL: return $this->_level;
            case self::FLD_LOGFILE: return $this->_logfile;
            case self::FLD_FROMPOS: return number_format($this->_frompos / 1024, 2);
            case self::FLD_FROMINPUT: return $this->_frominput;
            case self::FLD_BLKSIZE: return $this->_blksize;
            case self::FLD_OUTMESG:
                $repl = array('%%totallines%%' => number_format($this->_totallines),
                    '%%outlines%%'   => number_format($this->_outlines),
                    '%%level%%'      => $this->LEVEL_DESCR[$this->_level]
                );
                return DMsg::UIStr('service_logresnote', $repl) . ' ' . $this->_outmesg;
            case self::FLD_TOTALFOUND: return $this->_outlines;
            case self::FLD_FILE_SIZE: return number_format($this->_filesize / 1024, 2);

            default: die("Illegal entry! field = $field");
        }
    }

    public function GetLogOutput()
    {
        return $this->_output;
    }

    public function AddLogEntry($level, $time, $message)
    {
        $this->_outlines ++;
        $buf = '<tr><td>' . $time . '</td><td';
        switch ($level) {
            case LogFilter::LEVEL_ERR:
                $buf .= ' class="danger">ERROR';
                break;
            case LogFilter::LEVEL_WARN:
                $buf .= ' class="warning">WARN';
                break;
            case LogFilter::LEVEL_NOTICE:
                $buf .= ' class="info">NOTICE';
                break;
            case LogFilter::LEVEL_INFO:
                $buf .= '>INFO';
                break;
            default: $buf .= '>DEBUG';
        }
        $buf .= '</td><td>' . $message . '</td></tr>' . "\n";
        $this->_output .= $buf;
    }

    public function Set($field, $value)
    {
        switch ($field) {
            case self::FLD_LEVEL: $this->_level = $value;
                break;
            case self::FLD_FROMPOS: $this->_frompos = $value;
                break;
            case self::FLD_FROMINPUT: $this->_frominput = $value;
                break;
            case self::FLD_TOPOS: $this->_topos = $value;
                break;
            case self::FLD_TOTALSEARCHED: $this->_totallines = $value;
                break;
            case self::FLD_FILE_SIZE: $this->_filesize = $value;
                break;
        }
    }

    public function SetRange($from, $size)
    {
        if ($from < 0 && $from !== self::POS_FILEEND) {
            $from = 0;
        }
        $this->_frominput = $from;
        $this->_blksize = $size;
        $this->_output = '';
    }

    public function SetMesg($mesg)
    {
        $this->_outmesg = $mesg;
    }

}

class LogViewer
{

    public static function GetDashErrLog($errorlogfile)
    {
        $filter = new LogFilter($errorlogfile);
        $filter->Set(LogFilter::FLD_LEVEL, LogFilter::LEVEL_NOTICE);
        $filter->SetRange(LogFilter::POS_FILEEND, 20);
        self::loadErrorLog($filter);
        return $filter;
    }

    public static function GetErrLog($errorlogfile)
    {
        // get from input
        $filename = UIBase::GrabGoodInput('any', 'filename');
        if ($filename == '') {
            return self::GetDashErrLog($errorlogfile);
		}

        // todo: validate
        $level = UIBase::GrabGoodInput('ANY', 'sellevel', 'int');
        $startinput = UIBase::GrabGoodInput('any', 'startpos', 'float');
        $block = UIBase::GrabGoodInput('any', 'blksize', 'float');
        $act = UIBase::GrabGoodInput('any', 'act');

        switch ($act) {
            case 'begin':
                $startinput = 0;
                break;
            case 'end':
                $startinput = LogFilter::POS_FILEEND;
                break;
            case 'prev':
                $startinput -= $block;
                break;
            case 'next':
                $startinput += $block;
                break;
        }
        $filter = new LogFilter($filename);

        $filter->Set(LogFilter::FLD_LEVEL, $level);
        $filter->SetRange($startinput, $block);
        $filter->SetMesg('');
        self::loadErrorLog($filter);
        return $filter;
    }

    private static function loadErrorLog($filter)
    {
        $logfile = $filter->Get(LogFilter::FLD_LOGFILE);
        if (($fd = fopen($logfile, 'r')) == false) {
            $filter->SetMesg(DMsg::Err('err_failreadfile') . ': ' . $filter->Get(LogFilter::FLD_LOGFILE));
            return;
        }

        $frominput = $filter->Get(LogFilter::FLD_FROMINPUT);

        $block = $filter->Get(LogFilter::FLD_BLKSIZE) * 1024;
        $file_size = filesize($logfile);
        $filter->Set(LogFilter::FLD_FILE_SIZE, $file_size);

        $frompos = (int)(($frominput == LogFilter::POS_FILEEND) ? ($file_size - $block) : ($frominput * 1024));
        if ($frompos < 0) {
            $frompos = 0;
            $endpos = $file_size;
        } else {
            $endpos = $frompos + $block;
        }

        fseek($fd, $frompos);
        $filter->Set(LogFilter::FLD_FROMPOS, $frompos);

        $found = false;
        $totalLine = 0;

        $newlineTag = '[ERR[WAR[NOT[INF[DEB';
        $levels = array('E' => 1, 'W' => 2, 'N' => 3, 'I' => 4, 'D' => 5);
        $filterlevel = $filter->Get(LogFilter::FLD_LEVEL);

        $cur_level = '';
        $cur_time = '';
        $cur_mesg = '';

        while ($buffer = fgets($fd)) {
            // check if new line
            $c28 = substr($buffer, 28, 3);
            if ($c28 && strstr($newlineTag, $c28)) {
                // is new line
                $totalLine ++;
                if ($found) { // finish prior line
                    $filter->AddLogEntry($cur_level, $cur_time, $cur_mesg);
                    $found = false;
                }
                $cur_level = $levels[substr($c28, 0, 1)];
                if ($cur_level <= $filterlevel && preg_match("/^\d{4}-\d{2}-\d{2} /", $buffer)) {
                    // start a new line
                    $found = true;
                    $cur_time = substr($buffer, 0, 26);
                    $cur_mesg = htmlspecialchars(substr($buffer, strpos($buffer, ']', 27) + 2));
                }
            } elseif ($found) { // multi-line output
                $cur_mesg .= '<br>' . htmlspecialchars($buffer);
            }

            $curpos = ftell($fd);
            if ($curpos >= $endpos)
                break;
        }

        fclose($fd);
        if ($found)
            $filter->AddLogEntry($cur_level, $cur_time, $cur_mesg);

        $filter->Set(LogFilter::FLD_TOTALSEARCHED, $totalLine);
    }

}