Implementing automated compliance reporting for custom internal server status logs ledgers using dompdf library
Leveraging DOMPDF for Automated Server Status Log Compliance Reporting
For e-commerce platforms, maintaining a clear, auditable trail of internal server status and operational events is paramount for security and compliance. Manually generating reports from raw server logs is time-consuming and error-prone. This post details a robust, automated solution using PHP and the DOMPDF library to transform server status log entries into professional, PDF-formatted compliance reports.
Prerequisites and Setup
Before we begin, ensure you have a working PHP environment (version 7.4+ recommended) and Composer installed. We’ll need to install the DOMPDF library.
Navigate to your project’s root directory and execute the following Composer command:
This will download and install DOMPDF and its dependencies into your vendor/ directory.
composer require dompdf/dompdf
Structuring Server Log Data
Our compliance reports will be generated from structured log data. For this example, we’ll assume a simple CSV format for our server status logs. Each line represents an event with the following fields: timestamp, server_id, status_code, message, severity.
A sample log file (server_status.log) might look like this:
2023-10-27 10:00:05, server-01, 200, Service A operational, INFO 2023-10-27 10:01:15, server-02, 500, Database connection failed, ERROR 2023-10-27 10:02:30, server-01, 200, Service A healthy, INFO 2023-10-27 10:03:00, server-03, 404, Resource not found, WARN 2023-10-27 10:04:00, server-02, 200, Database connection re-established, INFO 2023-10-27 10:05:00, server-01, 503, Service B temporarily unavailable, ERROR
PHP Script for Report Generation
We’ll create a PHP script that reads this log file, processes the data, and then uses DOMPDF to render an HTML report, which is then converted to PDF. This script assumes the log file is in the same directory as the script, or you can provide an absolute path.
<?php
require_once 'vendor/autoload.php';
use Dompdf\Dompdf;
// --- Configuration ---
$logFilePath = 'server_status.log';
$reportTitle = 'Server Status Compliance Report';
$outputFileName = 'server_status_report_' . date('Ymd_His') . '.pdf';
$logEntriesPerPage = 50; // Number of log entries to display per page
// --- Helper function to format severity for better readability ---
function formatSeverity($severity) {
switch (strtoupper($severity)) {
case 'INFO':
return '<span style="color: green;">INFO</span>';
case 'WARN':
return '<span style="color: orange;">WARN</span>';
case 'ERROR':
return '<span style="color: red;">ERROR</span>';
default:
return htmlspecialchars($severity);
}
}
// --- Read and parse log data ---
$logData = [];
if (($handle = fopen($logFilePath, 'r')) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ',')) !== FALSE) {
// Basic validation: ensure we have the expected number of fields
if (count($data) === 5) {
$logData[] = [
'timestamp' => trim($data[0]),
'server_id' => trim($data[1]),
'status_code' => trim($data[2]),
'message' => trim($data[3]),
'severity' => trim($data[4]),
];
}
}
fclose($handle);
} else {
die("Error: Could not open log file: " . $logFilePath);
}
// --- Prepare HTML content for the report ---
$html = '<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>' . htmlspecialchars($reportTitle) . '</title>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; }
.report-header { text-align: center; margin-bottom: 30px; }
.report-title { font-size: 24px; font-weight: bold; margin-bottom: 10px; }
.report-date { font-size: 14px; color: #555; }
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.page-number {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
font-size: 10px;
color: #888;
padding-bottom: 10px;
}
.log-entry-error { background-color: #ffe6e6; }
.log-entry-warn { background-color: #fff0e6; }
</style>
</head>
<body>
<div class="report-header">
<h1 class="report-title">' . htmlspecialchars($reportTitle) . '</h1>
<p class="report-date">Generated on: ' . date('Y-m-d H:i:s') . '</p>
</div>';
// --- Generate table rows for log entries ---
$totalEntries = count($logData);
$totalPages = ceil($totalEntries / $logEntriesPerPage);
for ($page = 0; $page < $totalPages; $page++) {
// Start new page if not the first page
if ($page > 0) {
$html .= '<div class="page-break" style="page-break-before: always;"></div>';
$html .= '<div class="report-header">
<h1 class="report-title">' . htmlspecialchars($reportTitle) . '</h1>
<p class="report-date">Generated on: ' . date('Y-m-d H:i:s') . '</p>
</div>';
}
$html .= '<table>
<thead>
<tr>
<th>Timestamp</th>
<th>Server ID</th>
<th>Status</th>
<th>Severity</th>
<th>Message</th>
</tr>
</thead>
<tbody>';
$startIndex = $page * $logEntriesPerPage;
$endIndex = min(($startIndex + $logEntriesPerPage), $totalEntries);
for ($i = $startIndex; $i < $endIndex; $i++) {
$entry = $logData[$i];
$severityClass = '';
if (strtoupper($entry['severity']) === 'ERROR') {
$severityClass = 'log-entry-error';
} elseif (strtoupper($entry['severity']) === 'WARN') {
$severityClass = 'log-entry-warn';
}
$html .= '<tr class="' . $severityClass . '">
<td>' . htmlspecialchars($entry['timestamp']) . '</td>
<td>' . htmlspecialchars($entry['server_id']) . '</td>
<td>' . htmlspecialchars($entry['status_code']) . '</td>
<td>' . formatSeverity($entry['severity']) . '</td>
<td>' . htmlspecialchars($entry['message']) . '</td>
</tr>';
}
$html .= '</tbody>
</table>';
// Add page number
$html .= '<div class="page-number">Page ' . ($page + 1) . ' of ' . $totalPages . '</div>';
}
$html .= '</body>
</html>';
// --- Instantiate and use DOMPDF ---
$dompdf = new Dompdf();
$dompdf->loadHtml($html);
// (Optional) Set paper size and orientation
// $dompdf->setPaper('A4', 'landscape');
// Render the HTML as PDF
$dompdf->render();
// Output the generated PDF to Browser
$dompdf->stream($outputFileName, ["Attachment" => false]); // Set to true to force download
?>
Explanation of the Script
1. Autoloader Inclusion: require_once 'vendor/autoload.php'; loads the DOMPDF library and its dependencies.
2. Configuration: Key variables like the log file path, report title, and output filename are defined. The $logEntriesPerPage variable controls pagination.
3. Log Parsing: The script opens the specified CSV log file, reads it line by line using fgetcsv, and stores each valid entry (checking for 5 fields) in the $logData array. Error handling for file opening is included.
4. HTML Generation: A basic HTML structure is built. This includes a header with the report title and generation date, and a table to display the log entries.
5. Pagination Logic: The script calculates the total number of pages required based on the total log entries and the configured entries per page. It then iterates through each page, adding a page break and repeating the header for subsequent pages.
6. Styling: Inline CSS is used for basic styling of the report, including table borders, header alignment, and distinct styling for ERROR and WARN severity levels. The formatSeverity function applies color to severity text.
7. DOMPDF Integration:
* An instance of Dompdf is created.
* $dompdf->loadHtml($html); loads the generated HTML content.
* $dompdf->setPaper('A4', 'landscape'); (commented out) shows how you can specify paper size and orientation.
* $dompdf->render(); processes the HTML and prepares it for PDF output.
* $dompdf->stream($outputFileName, ["Attachment" => false]); outputs the PDF. Setting "Attachment" => false will display the PDF in the browser; setting it to true will force a download.
8. Security Note: All dynamic content inserted into the HTML is escaped using htmlspecialchars() to prevent potential cross-site scripting (XSS) vulnerabilities if log messages were to contain malicious HTML/JavaScript. The formatSeverity function also uses htmlspecialchars for its default case.
Automating the Report Generation
To fully automate this process, you can integrate this script into a cron job or a scheduled task. For example, to run the report generation script daily at 2 AM, you would add the following line to your crontab:
0 2 * * * /usr/bin/php /path/to/your/project/generate_report.php >> /path/to/your/project/logs/cron.log 2>&1
This command executes the PHP script using the PHP CLI. The output redirection (>> ... 2>&1) captures both standard output and errors into a log file, which is crucial for debugging scheduled tasks.
Advanced Considerations and Enhancements
- Dynamic Log Sources: Instead of a static CSV, you could adapt the script to read logs from a database, a centralized logging system (like ELK stack or Splunk), or directly from server APIs.
- Filtering and Summarization: Implement logic to filter logs by date range, server, severity, or to generate summary statistics (e.g., number of errors per server).
- Templating Engines: For more complex HTML structures, consider using a templating engine like Twig or Blade to separate presentation logic from PHP code.
- Error Handling and Notifications: Enhance error handling for log parsing and PDF generation. Implement email notifications upon successful report generation or in case of failures.
- Secure Storage: If reports contain sensitive information, ensure they are stored securely and access is restricted. Consider encrypting generated PDFs.
- Configuration Management: Move configuration settings (log paths, output directories, email recipients) to a separate configuration file (e.g., .env, JSON, or INI) for easier management.
- Internationalization (i18n): If your e-commerce platform serves a global audience, consider internationalizing date/time formats and text within the report.
- Custom Fonts: DOMPDF supports custom fonts. You can embed specific fonts for branding or better readability by following its documentation.
By automating the generation of server status compliance reports, e-commerce businesses can significantly improve their operational visibility, streamline auditing processes, and ensure adherence to regulatory requirements with minimal manual effort.