Created
September 25, 2024 10:16
-
-
Save pingpoli/fa7644397d507e4f38432d77320259ef to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$logfiles = [ | |
"/home/user/logs/php.log" | |
]; | |
$apacheLogFiles = [ | |
"/var/log/apache2/error.log" | |
]; | |
// after this many lines in the log file a warning will be included in the e-mail that the log file is getting long | |
$lengthWarning = 100; | |
const SMTP_HOST = "YOUR_SMTP_HOST"; | |
const SMTP_USERNAME = "YOUR_SMTP_USERNAME"; | |
const SMTP_PASSWORD = "YOUR_SMTP_PASSWORD"; | |
// 25 hours because time changes might mess this up otherwise, reporting errors twice might be less bad than missing some on a single day of the year? | |
$last25Hours = time()-25*60*60; | |
$str = "PHP errors have occured in the last 25 hours:<br><br>".PHP_EOL; | |
$errorCounter = 0; | |
// normal log files | |
foreach ( $logfiles as $logfile ) | |
{ | |
$file = fopen( $logfile , "r" ); | |
if ( $file ) | |
{ | |
$errors = []; | |
$linesCounter = 0; | |
while ( ( $line = fgets( $file ) ) !== false ) | |
{ | |
$time = substr( $line , 0 , strpos( $line , " >" ) ); | |
$timestamp = strtotime( $time ); | |
if ( $timestamp > $last25Hours ) | |
{ | |
$backtraceStr = ""; | |
if ( ( $pos = strpos( $line , "backtrace: " ) ) != false ) | |
{ | |
// add the normal error | |
$error = substr( $line , 0 , $pos-3 ); | |
$backtraceStr = $error."<br>".PHP_EOL; | |
// format backtrace | |
$backtrace = substr( $line , $pos+11 ); | |
$json = json_decode( $backtrace ); | |
for ( $i = 0 ; $i < count($json) ; ++$i ) | |
{ | |
$backtraceStr .= " ".$json[$i]->file.":".$json[$i]->line; | |
if ( $i != count($json)-1 ) $backtraceStr .= "<br>".PHP_EOL; | |
} | |
} | |
else | |
{ | |
$backtraceStr = $line; | |
} | |
$errors[] = $backtraceStr; | |
$errorCounter++; | |
} | |
$linesCounter++; | |
} | |
if ( count( $errors ) > 0 ) | |
{ | |
$str .= "<b>".$logfile."</b>:<br>".PHP_EOL; | |
foreach ( $errors as $error ) | |
{ | |
$str .= $error."<br>".PHP_EOL; | |
} | |
if ( $linesCounter > $lengthWarning ) | |
{ | |
$str .= "<b>WARNING</b> > This logfile is getting long.<br>".PHP_EOL; | |
} | |
$str .= "<br>".PHP_EOL; | |
} | |
fclose( $file ); | |
} | |
} | |
$str .= "Apache Error Logs:<br><br>".PHP_EOL; | |
// apache log files | |
foreach ( $apacheLogFiles as $apacheLogFile ) | |
{ | |
$file = fopen( $apacheLogFile , "r" ); | |
if ( $file ) | |
{ | |
$errors = []; | |
$attemptedFilenames = []; | |
$linesCounter = 0; | |
while ( ( $line = fgets( $file ) ) !== false ) | |
{ | |
$time = substr( $line , 1 , strpos( $line , "]" )-1 ); | |
$parts = explode( " " , $time ); | |
// convert the time to something strtotime can understand | |
$time = $parts[1]." ".$parts[2]." ".$parts[4]." ".substr( $parts[3] , 0 , strpos( $parts[3] , "." ) ); | |
$timestamp = strtotime( $time ); | |
// not needed, the server rotates the log file daily anyway | |
// if ( $timestamp > $last25Hours ) | |
{ | |
// all these errors look something like this | |
// [Sat Sep 21 20:03:14.424470 2024] [php7:error] [pid 0:tid 0] [client IP] script '/var/www/wp.php' not found or unable to stat | |
// apparently there can be some slightly different "not found" lines without the single quotes, so exclude them here | |
if ( strpos( $line , "not found or unable to stat" ) !== false && strpos( $line , "'" ) !== false ) | |
{ | |
// find the string between the single quotes | |
$attemptedFilename = substr( $line , strpos( $line , "'" )+1 , strrpos( $line , "'" )-strpos( $line , "'" )-1 ); | |
$attemptedFilename = str_replace( "/var/www/" , "" , $attemptedFilename ); | |
$attemptedFilenames[] = $attemptedFilename; | |
$errorCounter++; | |
} | |
else | |
{ | |
$errors[] = $line; | |
$errorCounter++; | |
} | |
} | |
$linesCounter++; | |
} | |
if ( count( $errors ) > 0 || count( $attemptedFilenames ) > 0 ) | |
{ | |
$str .= "<b>".$apacheLogFile."</b>:<br>".PHP_EOL; | |
foreach ( $errors as $error ) | |
{ | |
$str .= $error."<br>".PHP_EOL; | |
} | |
if ( count( $attemptedFilenames ) > 0 ) | |
{ | |
$str .= "<b>People tried to access the following files</b>:<br>".PHP_EOL; | |
foreach ( $attemptedFilenames as $attemptedFilename ) | |
{ | |
$str .= $attemptedFilename."<br>".PHP_EOL; | |
} | |
} | |
// if ( $linesCounter > $lengthWarning ) | |
// { | |
// $str .= "<b>WARNING</b> > This logfile is getting long.<br>".PHP_EOL; | |
// } | |
$str .= "<br>".PHP_EOL; | |
} | |
fclose( $file ); | |
} | |
} | |
if ( $errorCounter > 0 ) | |
{ | |
require( "phplibs/Exception.php" ); | |
require( "phplibs/PHPMailer.php" ); | |
require( "phplibs/SMTP.php" ); | |
sendEmail( $str ); | |
} | |
function sendEmail( $str ) | |
{ | |
$mail = new PHPMailer\PHPMailer\PHPMailer( true ); | |
try | |
{ | |
// disable debug output | |
$mail->SMTPDebug = 0; | |
$mail->isSMTP(); | |
$mail->Host = SMTP_HOST; | |
$mail->SMTPAuth = true; | |
$mail->Username = SMTP_USERNAME; | |
$mail->Password = SMTP_PASSWORD; | |
$mail->SMTPSecure = "tls"; | |
$mail->Port = 587; | |
// recipients | |
$mail->setFrom( "[email protected]" , "PHP Logger" ); | |
$mail->addAddress( "[email protected]" , "User" ); | |
// content | |
$mail->isHTML( true ); | |
$mail->Subject = "PHP Logger"; | |
$mail->Body = $str; | |
$mail->AltBody = $str; | |
// send | |
$mail->send(); | |
return true; | |
} | |
catch ( PHPMailer\PHPMailer\Exception $e ) | |
{ | |
error_log( "PHPMailer > failed to send email, error: ".$mail->ErrorInfo ); | |
return false; | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment