• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Implementing automated compliance reporting for custom internal server status logs ledgers using custom PhpSpreadsheet components

Implementing automated compliance reporting for custom internal server status logs ledgers using custom PhpSpreadsheet components

Leveraging PhpSpreadsheet for Automated Internal Server Log Compliance Reporting

Maintaining auditable logs for internal server status and operations is a critical, yet often manual, compliance requirement. This post details the implementation of a custom WordPress plugin component that automates the generation of detailed compliance reports in spreadsheet format using the PhpSpreadsheet library. We’ll focus on extracting specific server status data, transforming it into a structured format, and programmatically populating an Excel (XLSX) file for easy distribution and archival.

Data Source: Custom Server Status Logging

For this solution, we assume a custom logging mechanism is in place that records key server status metrics. This could be a custom database table, a series of log files parsed by a separate script, or even data retrieved via WP-CLI commands. For demonstration purposes, we’ll simulate fetching data from a hypothetical WordPress transient or option that stores an array of server status entries. Each entry might contain:

  • Timestamp of the status check.
  • Server hostname or identifier.
  • CPU utilization percentage.
  • Memory utilization percentage.
  • Disk space free (in GB).
  • Service status (e.g., ‘running’, ‘stopped’, ‘degraded’).
  • Any critical error messages logged during the interval.

Let’s assume our data is stored in a WordPress option named my_server_status_logs, which is an array of associative arrays.

Setting up PhpSpreadsheet in a WordPress Plugin

The first step is to ensure PhpSpreadsheet is available within your WordPress plugin’s environment. The most robust method is using Composer to manage dependencies. If your plugin doesn’t already have a composer.json file, create one in your plugin’s root directory.

Composer Configuration

Create or update your composer.json file:

{
    "name": "your-vendor/your-plugin-name",
    "description": "Custom server log reporting plugin.",
    "type": "wordpress-plugin",
    "license": "GPL-2.0-or-later",
    "require": {
        "php": ">=7.2",
        "phpoffice/phpspreadsheet": "^1.29"
    },
    "autoload": {
        "psr-4": {
            "YourPlugin\\": "includes/"
        }
    }
}

After creating/updating composer.json, run Composer to install the library and generate the autoloader:

composer install

This will create a vendor/ directory. You need to include the Composer autoloader in your plugin’s main file or an included bootstrap file.

Including the Autoloader

In your main plugin file (e.g., your-plugin-name.php), add the following line before any classes or functions that use PhpSpreadsheet:

require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload.php';

Ensure your plugin’s classes are also autoloaded by Composer as defined in the autoload section of composer.json. For example, a class ServerReporter in includes/ServerReporter.php would be accessible via new YourPlugin\ServerReporter().

Generating the Compliance Report

We’ll create a class, say ServerReporter, responsible for fetching data and generating the XLSX file. This class will utilize PhpSpreadsheet’s writer components.

The ServerReporter Class

Create a file includes/ServerReporter.php with the following content:

<?php
namespace YourPlugin;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;

class ServerReporter {

    private $log_option_name = 'my_server_status_logs';

    /**
     * Fetches raw server status log data.
     * In a real scenario, this might query a DB or parse files.
     *
     * @return array
     */
    private function get_log_data() {
        $logs = get_option( $this->log_option_name, [] );
        // Ensure it's an array and filter out any malformed entries if necessary
        if ( ! is_array( $logs ) ) {
            return [];
        }
        // Example: Filter logs for the last 24 hours if needed
        // $cutoff_time = time() - DAY_IN_SECONDS;
        // $logs = array_filter($logs, function($log) use ($cutoff_time) {
        //     return isset($log['timestamp']) && $log['timestamp'] > $cutoff_time;
        // });
        return array_values($logs); // Re-index array
    }

    /**
     * Generates the XLSX report and returns it as a string.
     *
     * @return string The XLSX file content as a string.
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     */
    public function generate_report() {
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle('Server Status Compliance');

        // Fetch data
        $log_data = $this->get_log_data();

        // Define headers
        $headers = [
            'Timestamp',
            'Server',
            'CPU (%)',
            'Memory (%)',
            'Disk Free (GB)',
            'Service Status',
            'Critical Errors'
        ];

        // Apply headers to the sheet
        $sheet->fromArray([$headers], NULL, 'A1');

        // Style headers
        $header_style_array = [
            'font' => [
                'bold' => true,
                'color' => ['argb' => 'FFFFFFFF'], // White text
            ],
            'fill' => [
                'fillType' => Fill::FILL_SOLID,
                'startColor' => ['argb' => 'FF4F81BD'], // Blue background
            ],
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER,
                'vertical' => Alignment::VERTICAL_CENTER,
            ],
            'borders' => [
                'bottom' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN],
            ]
        ];
        $sheet->getStyle('A1:' . $sheet->getCellByColumnAndRow(count($headers), 1)->getColumn() . '1')->applyFromArray($header_style_array);

        // Populate data rows
        $row_num = 2; // Start from the second row
        foreach ( $log_data as $entry ) {
            $sheet->setCellValueByColumnAndRow(1, $row_num, date('Y-m-d H:i:s', $entry['timestamp'] ?? time()));
            $sheet->setCellValueByColumnAndRow(2, $row_num, $entry['hostname'] ?? 'N/A');
            $sheet->setCellValueByColumnAndRow(3, $row_num, $entry['cpu_usage'] ?? 0);
            $sheet->setCellValueByColumnAndRow(4, $row_num, $entry['memory_usage'] ?? 0);
            $sheet->setCellValueByColumnAndRow(5, $row_num, $entry['disk_free_gb'] ?? 0);
            $sheet->setCellValueByColumnAndRow(6, $row_num, $entry['service_status'] ?? 'unknown');
            $sheet->setCellValueByColumnAndRow(7, $row_num, $entry['critical_errors'] ?? '');

            // Basic conditional formatting for critical errors
            if ( ! empty( $entry['critical_errors'] ) ) {
                $sheet->getStyle('G' . $row_num)->getFont()->setColor(new \PhpOffice\PhpSpreadsheet\Style\Color(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED));
            }

            $row_num++;
        }

        // Auto-size columns for better readability
        foreach (range('A', $sheet->getHighestColumn()) as $columnID) {
            $sheet->getColumnDimension($columnID)->setAutoSize(true);
        }
        // Adjust specific column widths if needed
        $sheet->getColumnDimension('G')->setWidth(50); // Wider for error messages

        // Create writer and output
        $writer = new Xlsx($spreadsheet);
        ob_start(); // Start output buffering
        $writer->save('php://output');
        $excel_content = ob_get_clean(); // Get buffered content

        return $excel_content;
    }

    /**
     * Triggers the report generation and forces download.
     */
    public function download_report() {
        try {
            $report_content = $this->generate_report();
            $filename = 'server-compliance-report-' . date('YmdHis') . '.xlsx';

            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            header('Content-Disposition: attachment;filename="' . $filename . '"');
            header('Cache-Control: max-age=0');
            // If you're running in a framework, you might need to adjust how headers are sent.
            // For WordPress, this is typically done via an AJAX action or a direct URL handler.

            echo $report_content;
            exit; // Important to stop further WordPress execution

        } catch (\Exception $e) {
            // Log the error and potentially display a user-friendly message
            error_log('Error generating server compliance report: ' . $e->getMessage());
            wp_die('Failed to generate report. Please check server logs for details.');
        }
    }
}

Integrating with WordPress

To make this report generation accessible, we can hook it into WordPress. Common methods include:

  • An AJAX action triggered from the WordPress admin area (e.g., a button on a custom settings page).
  • A WP-CLI command.
  • A direct URL endpoint (less recommended for security unless properly authenticated).

AJAX Endpoint Example

Add the following code to your plugin’s main file or an included file to handle an AJAX request:

// In your main plugin file (e.g., your-plugin-name.php)
add_action( 'wp_ajax_generate_server_report', function() {
    if ( ! current_user_can( 'manage_options' ) ) { // Ensure user has capability
        wp_send_json_error( 'Unauthorized access.' );
    }

    check_ajax_referer( 'generate_report_nonce', 'nonce' ); // Security nonce check

    $reporter = new \YourPlugin\ServerReporter();
    try {
        // The download_report method handles headers and output directly.
        // For AJAX, we might want to return the content or a success message.
        // Let's modify download_report slightly for AJAX or create a new method.

        // For simplicity here, we'll call generate_report and return content.
        // A real AJAX handler would likely return JSON with a download URL or the file content.
        // The direct download_report method is better suited for a direct URL access.

        // If you want to trigger download directly via AJAX, you'd need to
        // return a JSON response with a URL to a dedicated handler.
        // Or, if the AJAX call itself is expected to download, it's tricky.
        // The `download_report` method is designed for direct HTTP response.

        // Let's assume a separate handler for direct download triggered by JS.
        // For this AJAX example, we'll just confirm success.
        $reporter->generate_report(); // Generate to ensure no errors
        wp_send_json_success( 'Report generated successfully. Prepare for download.' );

    } catch ( \Exception $e ) {
        error_log( 'AJAX Server Report Error: ' . $e->getMessage() );
        wp_send_json_error( 'Failed to generate report.' );
    }
});

// To trigger the download directly via a URL (e.g., /wp-admin/admin-ajax.php?action=download_server_report)
add_action( 'admin_init', function() {
    if ( isset( $_GET['action'] ) && $_GET['action'] === 'download_server_report' ) {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Unauthorized access.' );
        }
        // Optional: Add nonce verification here as well if needed for security
        // check_ajax_referer( 'download_report_nonce' );

        $reporter = new \YourPlugin\ServerReporter();
        $reporter->download_report();
    }
});

// Add a button to a settings page or dashboard widget to trigger this.
// Example JavaScript for an AJAX button:
/*
jQuery(document).ready(function($) {
    $('#generate-report-button').on('click', function(e) {
        e.preventDefault();
        var button = $(this);
        var nonce = button.data('nonce'); // Assuming nonce is set as a data attribute

        button.text('Generating...');
        button.prop('disabled', true);

        $.ajax({
            url: ajaxurl, // WordPress AJAX URL
            type: 'POST',
            data: {
                action: 'generate_server_report',
                nonce: nonce
            },
            success: function(response) {
                if (response.success) {
                    // Redirect to the download URL or open in new tab
                    window.open('', '_blank');
                    button.text('Generate Report');
                    button.prop('disabled', false);
                } else {
                    alert('Error: ' + response.data);
                    button.text('Generate Report');
                    button.prop('disabled', false);
                }
            },
            error: function(jqXHR, textStatus, errorThrown) {
                alert('AJAX Error: ' + textStatus);
                button.text('Generate Report');
                button.prop('disabled', false);
            }
        });
    });
});
*/

In the example above, the AJAX action generate_server_report is primarily for validation and confirmation. The actual download is triggered by a separate URL endpoint admin-ajax.php?action=download_server_report, which is then called by JavaScript after the AJAX confirmation. This separation ensures that the browser correctly handles the file download initiated by a direct HTTP response, rather than an AJAX response.

Advanced Considerations and Best Practices

Error Handling and Logging

Robust error handling is crucial. The `try-catch` block in `download_report` catches exceptions from PhpSpreadsheet. Ensure these errors are logged using WordPress’s error_log() or a more sophisticated logging plugin. For AJAX requests, use wp_send_json_error() to return meaningful error messages to the client.

Security

Always validate user capabilities (e.g., current_user_can('manage_options')) and use nonces (check_ajax_referer()) for AJAX actions to prevent unauthorized access and cross-site request forgery (CSRF) attacks. For direct URL endpoints, ensure proper authentication and authorization checks are in place.

Performance

For very large datasets, generating spreadsheets can be memory-intensive. PhpSpreadsheet offers a “XlsxWriter” which can be more memory-efficient for large files, though it might have slightly different feature support. Consider implementing pagination or filtering if your log data grows excessively. Alternatively, use background job processing (e.g., via WP-Cron or a dedicated queue system) for report generation to avoid timing out the user’s request.

Customization

PhpSpreadsheet offers extensive styling options. You can customize fonts, colors, borders, number formats, and even add charts. For compliance, ensure timestamps are in a standard format, numerical data is correctly formatted (e.g., percentages), and critical issues are visually highlighted.

Data Source Abstraction

The get_log_data() method is a placeholder. In a production environment, abstract this method to fetch data from your actual logging source (database, log files, external APIs). This makes the reporting component reusable and easier to test.

By integrating PhpSpreadsheet into a custom WordPress plugin, you can automate the generation of detailed, professional compliance reports directly from your internal server status logs, significantly reducing manual effort and improving auditability.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Reducing database query bloat in Sage Roots modern environments layouts using custom lazy loaders
  • Performance Optimization: Tuning PHP-FPM and opcache pools for high-concurrency Firebase Realtime DB handlers
  • Reducing Largest Contentful Paint (LCP) by optimizing custom script enqueuing structures in legacy plugins
  • How to implement native Redis caching layers for high-volume custom taxonomy queries in Carbon Fields custom wrappers
  • Building secure B2B pricing grids with custom REST API Controllers endpoints and role overrides

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (48)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (182)
  • WordPress Plugin Development (197)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • Reducing database query bloat in Sage Roots modern environments layouts using custom lazy loaders
  • Performance Optimization: Tuning PHP-FPM and opcache pools for high-concurrency Firebase Realtime DB handlers
  • Reducing Largest Contentful Paint (LCP) by optimizing custom script enqueuing structures in legacy plugins

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala