'Operating System', 'value' => $os, ]; // Web Server and Version $webServer = $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown'; $systemInfo[] = [ 'name' => 'Web Server', 'value' => $webServer, ]; // Kernel and Version $kernelVersion = php_uname('r'); $systemInfo[] = [ 'name' => 'Kernel Version', 'value' => $kernelVersion, ]; // Database and Version $dbVersion = $mysqli->server_info; $systemInfo[] = [ 'name' => 'Database Version', 'value' => $dbVersion, ]; // Section: PHP Extensions $phpExtensions = []; $extensions = [ 'php-mailparse' => 'mailparse', 'php-imap' => 'imap', 'php-mysqli' => 'mysqli', 'php-intl' => 'intl', 'php-curl' => 'curl', 'php-mbstring' => 'mbstring', 'php-gd' => 'gd', ]; foreach ($extensions as $name => $ext) { $loaded = extension_loaded($ext); $phpExtensions[] = [ 'name' => "$name installed", 'passed' => $loaded, 'value' => $loaded ? 'Installed' : 'Not Installed', ]; } // Section: PHP Configuration $phpConfig = []; // Check if shell_exec is enabled $disabled_functions = explode(',', ini_get('disable_functions')); $disabled_functions = array_map('trim', $disabled_functions); $shell_exec_enabled = !in_array('shell_exec', $disabled_functions); $phpConfig[] = [ 'name' => 'shell_exec is enabled', 'passed' => $shell_exec_enabled, 'value' => $shell_exec_enabled ? 'Enabled' : 'Disabled', ]; // Check upload_max_filesize and post_max_size >= 500M function return_bytes($val) { $val = trim($val); $unit = strtolower(substr($val, -1)); $num = (float)$val; switch ($unit) { case 'g': $num *= 1024; case 'm': $num *= 1024; case 'k': $num *= 1024; } return $num; } $required_bytes = 500 * 1024 * 1024; // 500M in bytes $upload_max_filesize = ini_get('upload_max_filesize'); $post_max_size = ini_get('post_max_size'); $upload_passed = return_bytes($upload_max_filesize) >= $required_bytes; $post_passed = return_bytes($post_max_size) >= $required_bytes; $phpConfig[] = [ 'name' => 'upload_max_filesize >= 500M', 'passed' => $upload_passed, 'value' => $upload_max_filesize, ]; $phpConfig[] = [ 'name' => 'post_max_size >= 500M', 'passed' => $post_passed, 'value' => $post_max_size, ]; // PHP Memory Limit >= 128M $memoryLimit = ini_get('memory_limit'); $memoryLimitBytes = return_bytes($memoryLimit); $memoryLimitPassed = $memoryLimitBytes >= (128 * 1024 * 1024); $phpConfig[] = [ 'name' => 'PHP Memory Limit >= 128M', 'passed' => $memoryLimitPassed, 'value' => $memoryLimit, ]; // Max Execution Time >= 300 seconds $maxExecutionTime = ini_get('max_execution_time'); $maxExecutionTimePassed = $maxExecutionTime >= 300; $phpConfig[] = [ 'name' => 'Max Execution Time >= 300 seconds', 'passed' => $maxExecutionTimePassed, 'value' => $maxExecutionTime . ' seconds', ]; // Check PHP version >= 8.2.0 $php_version = PHP_VERSION; $php_passed = version_compare($php_version, '8.2.0', '>='); $phpConfig[] = [ 'name' => 'PHP version >= 8.2.0', 'passed' => $php_passed, 'value' => $php_version, ]; // Section: Shell Commands $shellCommands = []; if ($shell_exec_enabled) { $commands = ['whois', 'dig', 'git']; foreach ($commands as $command) { $which = trim(shell_exec("which $command 2>/dev/null")); $exists = !empty($which); $shellCommands[] = [ 'name' => "Command '$command' available", 'passed' => $exists, 'value' => $exists ? $which : 'Not Found', ]; } } else { // If shell_exec is disabled, mark commands as unavailable foreach (['whois', 'dig', 'git'] as $command) { $shellCommands[] = [ 'name' => "Command '$command' available", 'passed' => false, 'value' => 'shell_exec Disabled', ]; } } // Section: SSL Checks $sslChecks = []; // Check if accessing via HTTPS $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443; $sslChecks[] = [ 'name' => 'Accessing via HTTPS', 'passed' => $https, 'value' => $https ? 'Yes' : 'No', ]; // SSL Certificate Validity Check if ($https) { $streamContext = stream_context_create(["ssl" => ["capture_peer_cert" => true]]); $socket = @stream_socket_client("ssl://{$_SERVER['HTTP_HOST']}:443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext); if ($socket) { $params = stream_context_get_params($socket); $cert = $params['options']['ssl']['peer_certificate']; $certInfo = openssl_x509_parse($cert); $validFrom = $certInfo['validFrom_time_t']; $validTo = $certInfo['validTo_time_t']; $currentTime = time(); $certValid = ($currentTime >= $validFrom && $currentTime <= $validTo); $sslChecks[] = [ 'name' => 'SSL Certificate is valid', 'passed' => $certValid, 'value' => $certValid ? 'Valid' : 'Invalid or Expired', ]; } else { $sslChecks[] = [ 'name' => 'SSL Certificate is valid', 'passed' => false, 'value' => 'Unable to retrieve certificate', ]; } } else { $sslChecks[] = [ 'name' => 'SSL Certificate is valid', 'passed' => false, 'value' => 'Not using HTTPS', ]; } // Section: Domain Checks $domainChecks = []; // Check if the site has a valid FQDN $fqdn = $_SERVER['HTTP_HOST']; $isValidFqdn = (bool) filter_var('http://' . $fqdn, FILTER_VALIDATE_URL) && preg_match('/^[a-z0-9.-]+\.[a-z]{2,}$/i', $fqdn); $domainChecks[] = [ 'name' => 'Site has a valid FQDN', 'passed' => $isValidFqdn, 'value' => $fqdn, ]; // Section: File Permissions $filePermissions = []; // Check if web user has write access to webroot directory $webroot = $_SERVER['DOCUMENT_ROOT']; $writable = is_writable($webroot); $filePermissions[] = [ 'name' => 'Web user has write access to webroot directory', 'passed' => $writable, 'value' => $webroot, ]; // Section: Uploads Directory Stats $uploadsStats = []; // Define the uploads directory path $uploadsDir = __DIR__ . '/uploads'; // Adjust the path if needed if (is_dir($uploadsDir)) { // Function to recursively count files and calculate total size function getDirStats($dir) { $files = 0; $size = 0; $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); foreach ($iterator as $file) { if ($file->isFile()) { $files++; $size += $file->getSize(); } } return ['files' => $files, 'size' => $size]; } $stats = getDirStats($uploadsDir); $sizeInMB = round($stats['size'] / (1024 * 1024), 2); $uploadsStats[] = [ 'name' => 'Number of files in uploads directory', 'value' => $stats['files'], ]; $uploadsStats[] = [ 'name' => 'Total size of uploads directory (MB)', 'value' => $sizeInMB . ' MB', ]; } else { $uploadsStats[] = [ 'name' => 'Uploads directory exists', 'value' => 'Directory not found', ]; } // Section: Database Stats $databaseStats = []; // Get list of tables $tablesResult = $mysqli->query("SHOW TABLE STATUS"); if ($tablesResult) { $totalTables = 0; $totalFields = 0; $totalRows = 0; $totalSize = 0; $tableDetails = []; while ($table = $tablesResult->fetch_assoc()) { $tableName = $table['Name']; $tableRows = $table['Rows']; $dataLength = $table['Data_length']; $indexLength = $table['Index_length']; $tableSize = ($dataLength + $indexLength) / (1024 * 1024); // Size in MB // Get number of fields $fieldsResult = $mysqli->query("SHOW COLUMNS FROM `$tableName`"); $numFields = $fieldsResult->num_rows; $fieldsResult->free(); $totalTables++; $totalFields += $numFields; $totalRows += $tableRows; $totalSize += $tableSize; $tableDetails[] = [ 'name' => $tableName, 'fields' => $numFields, 'rows' => $tableRows, 'size' => round($tableSize, 2), ]; } $tablesResult->free(); $databaseStats[] = [ 'name' => 'Current Database Version', 'value' => CURRENT_DATABASE_VERSION, ]; $databaseStats[] = [ 'name' => 'Total number of tables', 'value' => $totalTables, ]; $databaseStats[] = [ 'name' => 'Total number of fields', 'value' => $totalFields, ]; $databaseStats[] = [ 'name' => 'Total number of rows', 'value' => $totalRows, ]; $databaseStats[] = [ 'name' => 'Total database size (MB)', 'value' => round($totalSize, 2) . ' MB', ]; } else { $databaseStats[] = [ 'name' => 'Database connection error', 'value' => $mysqli->error, ]; } // Section: Database Structure Comparison $dbComparison = []; // Path to the db.sql file $dbSqlFile = __DIR__ . '/db.sql'; if (file_exists($dbSqlFile)) { // Read the db.sql file $sqlContent = file_get_contents($dbSqlFile); // Remove comments and empty lines $lines = explode("\n", $sqlContent); $sqlStatements = []; $statement = ''; foreach ($lines as $line) { // Remove single-line comments $line = preg_replace('/--.*$/', '', $line); $line = preg_replace('/\/\*.*?\*\//', '', $line); // Skip empty lines if (trim($line) == '') { continue; } // Append line to the current statement $statement .= $line . "\n"; // Check if the statement ends with a semicolon if (preg_match('/;\s*$/', $line)) { $sqlStatements[] = $statement; $statement = ''; } } // Parse the CREATE TABLE statements $sqlTables = []; foreach ($sqlStatements as $sql) { if (preg_match('/CREATE TABLE\s+`?([^` ]+)`?\s*\((.*)\)(.*?);/msi', $sql, $match)) { $tableName = $match[1]; $columnsDefinition = $match[2]; // Extract column names and data types $columns = []; $columnLines = explode("\n", $columnsDefinition); foreach ($columnLines as $line) { $line = trim($line); // Skip empty lines and lines that do not define columns if ($line == '' || strpos($line, 'PRIMARY KEY') !== false || strpos($line, 'UNIQUE KEY') !== false || strpos($line, 'KEY') === 0 || strpos($line, 'CONSTRAINT') === 0 || strpos($line, ')') === 0) { continue; } // Remove trailing comma if present $line = rtrim($line, ','); // Match column definition if (preg_match('/^`([^`]+)`\s+(.+)/', $line, $colMatch)) { $colName = $colMatch[1]; $colDefinition = $colMatch[2]; // Extract the data type from the column definition $tokens = preg_split('/\s+/', $colDefinition); $colType = $tokens[0]; // Handle data types with parentheses (e.g., varchar(255), decimal(15,2)) if (preg_match('/^([a-zA-Z]+)\(([^)]+)\)/', $colType, $typeMatch)) { $colType = $typeMatch[1] . '(' . $typeMatch[2] . ')'; } $columns[$colName] = $colType; } } $sqlTables[$tableName] = $columns; } } // Get current database table structures $dbTables = []; $tablesResult = $mysqli->query("SHOW TABLES"); while ($row = $tablesResult->fetch_row()) { $tableName = $row[0]; $columnsResult = $mysqli->query("SHOW COLUMNS FROM `$tableName`"); $columns = []; while ($col = $columnsResult->fetch_assoc()) { $columns[$col['Field']] = $col['Type']; } $columnsResult->free(); $dbTables[$tableName] = $columns; } $tablesResult->free(); // Compare the structures foreach ($sqlTables as $tableName => $sqlColumns) { if (!isset($dbTables[$tableName])) { $dbComparison[] = [ 'name' => "Table `$tableName` missing in database", 'status' => 'Missing Table', ]; continue; } // Compare columns $dbColumns = $dbTables[$tableName]; foreach ($sqlColumns as $colName => $colType) { if (!isset($dbColumns[$colName])) { $dbComparison[] = [ 'name' => "Column `$colName` missing in table `$tableName`", 'status' => 'Missing Column', ]; } else { // Normalize data types for comparison $sqlColType = strtolower($colType); $dbColType = strtolower($dbColumns[$colName]); // Remove attributes and constraints $sqlColType = preg_replace('/\s+.*$/', '', $sqlColType); $dbColType = preg_replace('/\s+.*$/', '', $dbColType); // Remove additional attributes like unsigned, zerofill, etc. $sqlColType = preg_replace('/\s+unsigned|\s+zerofill|\s+binary/', '', $sqlColType); $dbColType = preg_replace('/\s+unsigned|\s+zerofill|\s+binary/', '', $dbColType); if ($sqlColType != $dbColType) { $dbComparison[] = [ 'name' => "Data type mismatch for `$colName` in table `$tableName`", 'status' => "Expected: $colType, Found: {$dbColumns[$colName]}", ]; } } } // Check for extra columns in the database that are not in the SQL file foreach ($dbColumns as $colName => $colType) { if (!isset($sqlColumns[$colName])) { $dbComparison[] = [ 'name' => "Extra column `$colName` in table `$tableName` not present in db.sql", 'status' => 'Extra Column', ]; } } } // Check for tables in the database not present in the db.sql file foreach ($dbTables as $tableName => $dbColumns) { if (!isset($sqlTables[$tableName])) { $dbComparison[] = [ 'name' => "Extra table `$tableName` in database not present in db.sql", 'status' => 'Extra Table', ]; } } } else { $dbComparison[] = [ 'name' => 'db.sql file not found', 'status' => 'File Missing', ]; } $mysqli->close(); ?>

Debug

Debugging


System Information

PHP Extensions and Configuration

PHP Extensions
PHP Configuration
Shell Commands
SSL Checks
Domain Checks
File Permissions

Database Structure Comparison

No discrepancies found between the database and db.sql file.

Uploads Directory Stats

Database Stats

Table Stats

Table Name Fields / Rows Size (MB)