├── VERSION ├── .gitattributes ├── header.php ├── .gitignore ├── README.md ├── foot.php ├── config.dist.php ├── head.php ├── login.php ├── functions.php └── index.php /VERSION: -------------------------------------------------------------------------------- 1 | 1.7 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore config file 2 | /config.php 3 | /test* 4 | 5 | # Ignoring directories 6 | # Both the directory itself and its contents will be ignored. 7 | test/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hMailServer Log Searcher 2 | Search hMailServer logs by keyword. Keyword can be string, IP, date/time, etc. 3 | 4 | The script loops through all files in hMailServer's Logs directory (path found via API), reads each line and if a matching keyword is found, displays the line and the log filename. 5 | 6 | # Instructions 7 | Copy config.dist.php to config.php and fill in the variables. -------------------------------------------------------------------------------- /foot.php: -------------------------------------------------------------------------------- 1 | 4 | Pálinkás jó reggelt kívánok!
"; 5 | $versionGitHub = file_get_contents('https://raw.githubusercontent.com/palinkas-jo-reggelt/hMailServer_Log_Searcher/main/VERSION'); 6 | $versionLocal = file_get_contents('VERSION'); 7 | if ((float)$versionLocal < (float)$versionGitHub) { 8 | echo " 9 | Upgrade to version ".trim($versionGitHub)." available at GitHub"; 10 | } 11 | echo " 12 | 13 | 14 | 15 | "; 16 | ?> -------------------------------------------------------------------------------- /config.dist.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /head.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | hMailServer Log Searcher 18 | 19 | 20 | 21 | 22 | 44 | 45 | 46 | 47 | 48 | 49 |
-------------------------------------------------------------------------------- /login.php: -------------------------------------------------------------------------------- 1 | 41 | 42 | 43 | 44 | 45 | 46 | Log In 47 | 48 | 49 | 53 | 54 | 55 |
56 |

Log In

57 |
" method="post"> 58 |
59 | 60 | 61 |
62 |
63 | 64 | 65 |
66 |
67 | 68 | 69 |
70 |
71 | 72 |
73 |
74 | "; 77 | echo "alert('Username/Password Invalid');"; 78 | echo ""; 79 | } 80 | ?> 81 |
82 | 83 | -------------------------------------------------------------------------------- /functions.php: -------------------------------------------------------------------------------- 1 | Authenticate("Administrator", $hMSAdminPass); 6 | return $hMS; 7 | } 8 | 9 | function redirect($url) { 10 | if (!headers_sent()) { 11 | header('Location: '.$url); 12 | exit; 13 | } else { 14 | echo ''; 17 | echo ''; exit; 20 | } 21 | } 22 | 23 | // https://www.php.net/manual/en/function.mb-detect-encoding.php#91051 24 | // Unicode BOM is U+FEFF, but after encoded, it will look like this. 25 | define ('UTF32_BIG_ENDIAN_BOM' , chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF)); 26 | define ('UTF32_LITTLE_ENDIAN_BOM', chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00)); 27 | define ('UTF16_BIG_ENDIAN_BOM' , chr(0xFE) . chr(0xFF)); 28 | define ('UTF16_LITTLE_ENDIAN_BOM', chr(0xFF) . chr(0xFE)); 29 | define ('UTF8_BOM' , chr(0xEF) . chr(0xBB) . chr(0xBF)); 30 | 31 | function detect_utf_encoding($fileName) { 32 | $text = file_get_contents($fileName); 33 | $first2 = substr($text, 0, 2); 34 | $first3 = substr($text, 0, 3); 35 | $first4 = substr($text, 0, 3); 36 | 37 | if ($first3 == UTF8_BOM) return 'UTF-8'; 38 | elseif ($first4 == UTF32_BIG_ENDIAN_BOM) return 'UTF-32BE'; 39 | elseif ($first4 == UTF32_LITTLE_ENDIAN_BOM) return 'UTF-32LE'; 40 | elseif ($first2 == UTF16_BIG_ENDIAN_BOM) return 'UTF-16BE'; 41 | elseif ($first2 == UTF16_LITTLE_ENDIAN_BOM) return 'UTF-16LE'; 42 | } 43 | 44 | // https://github.com/coax/hmailserver-webadmin/blob/master/hMailAdmin/include/log_functions.php#L100-L104 45 | function cleanString($str) { 46 | $search = array("\r\n", "'", '"', '<', '>', '[nl]', '{em}', '{/em}','\n'); 47 | $replace = array('', '', '', '<', '>', '
', '', '','
'); 48 | return str_replace($search, $replace, $str); 49 | } 50 | 51 | // https://github.com/coax/hmailserver-webadmin/blob/master/hMailAdmin/include/log_functions.php#L106-L120 52 | function cleanNonUTF8($str) { 53 | $regex = <<<'END' 54 | / 55 | ( 56 | (?: [\x00-\x7F] # single-byte sequences 0xxxxxxx 57 | | [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx 58 | | [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2 59 | | [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3 60 | ){1,100} # ...one or more times 61 | ) 62 | | . # anything else 63 | /x 64 | END; 65 | return preg_replace($regex, '$1', $str); 66 | } 67 | 68 | // https://stackoverflow.com/questions/2510434/format-bytes-to-kilobytes-megabytes-gigabytes#2510459 69 | function formatBytes($size, $precision = 1) { 70 | $base = log($size, 1024); 71 | $suffixes = array('Bytes', 'KB', 'MB', 'GB', 'TB'); 72 | return round(pow(1024, $base - floor($base)), $precision).' '.$suffixes[floor($base)]; 73 | } 74 | ?> 75 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | "; 30 | } else { 31 | $hMS = hMSAuthenticate(); 32 | $logFolder = $hMS->Settings->Directories->LogDirectory; 33 | $logFolder_hidden = ""; 34 | } 35 | if (isset($_GET['log_ext'])) { 36 | $log_ext = trim($_GET['log_ext']); 37 | $fileExtension_hidden = ""; 38 | } else { 39 | $log_ext = $defaultFileExt; 40 | $fileExtension_hidden = ""; 41 | } 42 | 43 | $logDate_array = array(); 44 | $logFile_array = array(); 45 | $logType_array = array(); 46 | if (is_dir($logFolder)) { 47 | if ($handle = opendir($logFolder)) { 48 | while(($file = readdir($handle)) !== FALSE) { 49 | if (preg_match("/\.(".$log_ext.")$/",$file)) { 50 | $fileNoDate = preg_replace("/_(([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9]))\.(".$log_ext.")|\.(".$log_ext.")/","",$file); 51 | if (!in_array($fileNoDate, $logType_array, true)){ 52 | array_push($logType_array, $fileNoDate); 53 | } 54 | if ((preg_match("/^".$byType."_(([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9]))\.(".$log_ext.")|^".$byType."\.(".$log_ext.")/",$file)) || ($byType === "All Log Types")) { 55 | preg_match('/(([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9]))/',$file,$matches); 56 | if (isset($matches[0])){ 57 | if (!in_array($matches[0], $logDate_array, true)){ 58 | array_push($logDate_array, $matches[0]); 59 | } 60 | } 61 | } 62 | $logFile_array[] = $file; 63 | } 64 | } 65 | closedir($handle); 66 | } 67 | } 68 | rsort($logDate_array); 69 | 70 | echo " 71 |
72 |
73 | 74 | 75 | 85 | 95 | 96 | ".$logFolder_hidden." 97 | 98 | 99 |
"; 100 | 101 | if (empty($search)) { 102 | echo " 103 |
104 |
105 | No Search Term Provided 106 |
"; 107 | } else { 108 | $start = microtime(true); 109 | $highlight = "/\w*?".$search."\w*/i"; 110 | $results = array(); 111 | $logIterator = 0; 112 | $lineIterator = 0; 113 | $fileSize = 0; 114 | $fileCount = 0; 115 | $invalidRegEx = false; 116 | 117 | foreach ($logFile_array as $logFile) { 118 | $logFileTypeBase = preg_replace("/_(([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9]))\.(".$log_ext.")$|\.(".$log_ext.")$/","",$logFile); 119 | $logFileDateBase = preg_replace("/\.(".$log_ext.")$/","",$logFile); 120 | if ((($byType === $logFileTypeBase) || ($byType === "All Log Types")) && ((preg_match($logDateRegEx,$logFileDateBase)) || ($byDate === "All Dates"))) { 121 | $fileName = $logFolder.DIRECTORY_SEPARATOR.$logFile; 122 | $logLineIterator = 0; 123 | $lineCounter = 0; 124 | $linePosition = 1; 125 | $data = array(); 126 | 127 | if (file_exists($fileName)) { 128 | $fileSize = $fileSize + filesize($fileName); 129 | $encoding = detect_utf_encoding($fileName); 130 | $file = fopen($fileName, "r"); 131 | if ($file) { 132 | $fileCount++; 133 | while(!feof($file)) { 134 | $line = fgets($file); 135 | if (!is_null($encoding)) { 136 | if ($lineCounter > 0) { 137 | $line = preg_replace('/[^\x00-\x7F]/', '', $line); 138 | } 139 | if ($encoding == "UTF-16LE") { 140 | $line = mb_convert_encoding ($line, "UTF-8", "UTF-16"); 141 | } else { 142 | $line = mb_convert_encoding ($line, "UTF-8", $encoding); 143 | } 144 | $lineCounter++; 145 | } 146 | // if (preg_match("/".$search."/iu",$line)) { 147 | $match = @preg_match("/".$search."/iu", $line, $lineMatches); 148 | if ($match === false) { 149 | $err = preg_last_error(); 150 | if($err == PREG_INTERNAL_ERROR) { 151 | $invalidRegEx = true; 152 | break; 153 | } 154 | } else if ($match) { 155 | 156 | $line = cleanString($line); 157 | $line = cleanNonUTF8($line); 158 | $lineIterator++; 159 | $line = preg_replace($highlight, "$0", $line); 160 | 161 | if (!isset($results[$logIterator])) { 162 | $results[$logIterator][0] = array($logFile, $logLineIterator); 163 | } 164 | $results[$logIterator][0][1] = $logLineIterator + 1; 165 | $results[$logIterator][1][] = array($linePosition, $line); 166 | 167 | $logLineIterator++; 168 | } else { 169 | // do nothing 170 | } 171 | $linePosition++; 172 | } 173 | fclose($file); 174 | } else { 175 | echo " 176 |
177 |
178 | Error opening log file: ".$logFile." 179 |
"; 180 | } 181 | $logIterator++; 182 | } else { 183 | echo " 184 |
185 |
186 | Log file not found: ".$logFile." 187 |
"; 188 | } 189 | } 190 | } 191 | 192 | $end = microtime(true); 193 | $time = number_format(($end - $start), 2); 194 | 195 | if ($lineIterator === 0) { 196 | echo " 197 |
198 |
"; 199 | if ($invalidRegEx) { 200 | echo " 201 | Invalid Regular Expression Used In Search"; 202 | } else { 203 | echo " 204 | No Results"; 205 | } 206 | echo " 207 |
"; 208 | } else { 209 | echo " 210 |
".number_format($lineIterator)." results found among ".$fileCount." files totalling ".formatBytes($fileSize)." searched in ".$time." seconds

211 |
"; 212 | foreach ($results as $result) { 213 | echo " 214 |
".$result[0][0]." : ".$result[0][1]." Results
"; 215 | foreach ($result[1] as $lineresult) { 216 | echo " 217 |
218 |
Line ".number_format($lineresult[0]).":
219 |
".$lineresult[1]."
220 |
"; 221 | } 222 | echo "
"; 223 | } 224 | echo " 225 |
"; 226 | } 227 | } 228 | echo " 229 |
230 |
"; 231 | 232 | include_once("foot.php"); 233 | ?> --------------------------------------------------------------------------------