From 17a426a0d27f2bc0e029f0cef2c3da9f31184c8c Mon Sep 17 00:00:00 2001 From: Joshua Ramon Enslin Date: Mon, 20 Jul 2020 11:17:25 +0200 Subject: [PATCH] Initial --- MDErrorReporter.php | 230 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 MDErrorReporter.php diff --git a/MDErrorReporter.php b/MDErrorReporter.php new file mode 100644 index 0000000..d2c113b --- /dev/null +++ b/MDErrorReporter.php @@ -0,0 +1,230 @@ + $toFormat Associative array containing information to + * be formatted. + * @param integer $level Indentation level. Defaults to 0. + * + * @return string + */ + final private function _formulateDebugMailSection(string $headline, array $toFormat, int $level = 0):string { + + $msg = ""; + if (!empty($headline)) { + if ($level === 0) { + $msg .= PHP_EOL . "## " . $headline; + $msg .= PHP_EOL . "----------------------" . PHP_EOL . PHP_EOL; + } + else $msg .= "$headline" . PHP_EOL; + } + + $longestKey = 0; + foreach ($toFormat as $key => $value) { + if (strlen((string)$key) + (4 * $level) > $longestKey) $longestKey = strlen((string)$key) + (4 * $level); + } + foreach ($toFormat as $key => $value) { + if (is_array($value)) { + $msg .= $this->_formulateDebugMailSection((string)$key, $value, $level + 1); + } + else if (is_object($value)) { + $msg .= sprintf("%-{$longestKey}s :: %s", $key, var_export($value, true)) . PHP_EOL; + } + else { + $msg .= sprintf("%-{$longestKey}s :: %s", $key, (string)$value) . PHP_EOL; + } + } + $msg .= PHP_EOL; + + return $msg; + + } + + /** + * Gets additional debugging information, e.g. RAM usage. + * + * @return array + */ + final public function getAdditionalDebuggingInfo():array { + + $output = [ + "Current memory usage" => $this->human_filesize((string)memory_get_usage()), + "Peak memory usage" => $this->human_filesize((string)memory_get_peak_usage()), + "Included / required files" => get_included_files(), + # "Allowed memory usage" => $this->human_filesize((string)ini_get("memory_limit")), + ]; + + return $output; + + } + + /** + * This function sends a mail to the specified address, containing relevant debug information. + * . + * + * @param string $to Recipient mail address. + * @param string $subject Optional subject of the notification. Defaults to "". + * @param string $description Optional text of the notification. Defaults to : "". + * @param array $contextInfo Context information that will be displayed in a + * key-value format at the start of the mail. + * + * @return void + */ + final public function sendDebugMail(string $to, string $subject = "", string $description = "", array $contextInfo = []):void { + + $subject = "[{$this->_context}]{$subject}[Controlled error notification]"; + + $msg = " +# Automated error message +========================= + "; + + if (!empty($contextInfo)) { + $msg .= $this->_formulateDebugMailSection("Context information", $contextInfo); + } + + if ($description != "") { + $msg .= "## Description" . PHP_EOL; + $msg .= "--------------" . PHP_EOL . PHP_EOL; + $msg .= "$description" . PHP_EOL; + } + + $msg .= $this->_formulateDebugMailSection("Debug backtrace", debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT)); + + // Append the contents of $_SERVER + if (!empty($_SERVER)) { + $msg .= $this->_formulateDebugMailSection("The current content of \$_SERVER", $_SERVER); + } + + // Append the contents of $_SESSION + if (session_status() == PHP_SESSION_ACTIVE) { + $msg .= $this->_formulateDebugMailSection("The current content of \$_SESSION", $_SESSION); + } + else $msg .= "No active session"; + + $msg .= $this->_formulateDebugMailSection("Additional debugging information", + $this->getAdditionalDebuggingInfo()); + + $msg .= PHP_EOL . PHP_EOL; + + $msg = shell_exec("echo " . escapeshellarg($msg) . " | gpg2 --always-trust --recipient " . escapeshellarg($to) . " --encrypt --armor --local-user 35CA0E31F6F44FB5 --sign"); + + // Set header + $header = [ + 'From' => $this->_contact_mail_addr, + 'X-Mailer' => 'PHP/' . phpversion() + ]; + + // Send email + mail("$to", "$subject", "$msg", $header); + + } + + /** + * Wrapper around MDErrorReporter::sendDebugMail that can handle a throwable. + * + * @param Throwable $exception Exception to report on. + * @param string $recipient Recipient mail address. + * @param string $addDesc Additional descriptive information. + * + * @return void + */ + final public function sendErrorReport(Throwable $exception, string $recipient, string $addDesc = ""):void { + + $subject = get_class($exception) . ": " . $exception->getCode(); + + $description = $addDesc; + $description .= $this->_formulateDebugMailSection("Detailed error information", $exception); + + $additionalContextInfo = [ + "Message" => $exception->getMessage(), + "File" => $exception->getFile(), + "Line" => $exception->getLine() + ]; + + $this->sendDebugMail($recipient, + $subject, + $description, + $additionalContextInfo + ); + + } + + /** + * Constructor. + * + * @param string $toolName Name of the current tool. + * @param string $contact_mail_addr Mail address for mail's from header. + * + * @return void + */ + public function __construct(string $toolName = "museum-digital (unspecified)", string $contact_mail_addr = "bugs-md") { + + $this->_context = $toolName; + $this->_contact_mail_addr = $contact_mail_addr; + + } + +}