mirror of https://github.com/itflow-org/itflow
Reworked the entire debugger, only grather nessesary info and database comparison to existing and db.sql works now
This commit is contained in:
parent
2250269820
commit
351bb484a7
920
admin_debug.php
920
admin_debug.php
|
|
@ -5,191 +5,503 @@ require_once "database_version.php";
|
||||||
|
|
||||||
require_once "config.php";
|
require_once "config.php";
|
||||||
|
|
||||||
$folderPath = 'uploads';
|
$checks = [];
|
||||||
|
|
||||||
function countFilesInDirectory($dir) {
|
// Section: System Information
|
||||||
$count = 0;
|
$systemInfo = [];
|
||||||
$size = 0;
|
|
||||||
$files = scandir($dir);
|
|
||||||
|
|
||||||
foreach ($files as $file) {
|
// Operating System and Version
|
||||||
if ($file === '.' || $file === '..') {
|
$os = php_uname();
|
||||||
continue;
|
$systemInfo[] = [
|
||||||
}
|
'name' => 'Operating System',
|
||||||
|
'value' => $os,
|
||||||
|
];
|
||||||
|
|
||||||
$filePath = $dir . '/' . $file;
|
// Web Server and Version
|
||||||
|
$webServer = $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown';
|
||||||
|
$systemInfo[] = [
|
||||||
|
'name' => 'Web Server',
|
||||||
|
'value' => $webServer,
|
||||||
|
];
|
||||||
|
|
||||||
if (is_file($filePath)) {
|
// Kernel and Version
|
||||||
$count++;
|
$kernelVersion = php_uname('r');
|
||||||
$size += filesize($filePath);
|
$systemInfo[] = [
|
||||||
} elseif (is_dir($filePath)) {
|
'name' => 'Kernel Version',
|
||||||
$result = countFilesInDirectory($filePath);
|
'value' => $kernelVersion,
|
||||||
$count += $result['count'];
|
];
|
||||||
$size += $result['size'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
// Database and Version
|
||||||
'count' => $count,
|
$dbVersion = $mysqli->server_info;
|
||||||
'size' => $size
|
$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',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to compare two arrays recursively and return the differences
|
// Section: PHP Configuration
|
||||||
function arrayDiffRecursive($array1, $array2) {
|
$phpConfig = [];
|
||||||
$diff = array();
|
|
||||||
|
|
||||||
foreach ($array1 as $key => $value) {
|
// Check if shell_exec is enabled
|
||||||
if (is_array($value)) {
|
$disabled_functions = explode(',', ini_get('disable_functions'));
|
||||||
if (!isset($array2[$key]) || !is_array($array2[$key])) {
|
$disabled_functions = array_map('trim', $disabled_functions);
|
||||||
$diff[$key] = $value;
|
$shell_exec_enabled = !in_array('shell_exec', $disabled_functions);
|
||||||
} else {
|
|
||||||
$recursiveDiff = arrayDiffRecursive($value, $array2[$key]);
|
$phpConfig[] = [
|
||||||
if (!empty($recursiveDiff)) {
|
'name' => 'shell_exec is enabled',
|
||||||
$diff[$key] = $recursiveDiff;
|
'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 {
|
} else {
|
||||||
if (!isset($array2[$key]) || $array2[$key] !== $value) {
|
// If shell_exec is disabled, mark commands as unavailable
|
||||||
$diff[$key] = $value;
|
foreach (['whois', 'dig', 'git'] as $command) {
|
||||||
}
|
$shellCommands[] = [
|
||||||
}
|
'name' => "Command '$command' available",
|
||||||
}
|
'passed' => false,
|
||||||
|
'value' => 'shell_exec Disabled',
|
||||||
return $diff;
|
];
|
||||||
}
|
|
||||||
|
|
||||||
// Function to load the table structures from an SQL dump file URL
|
|
||||||
function loadTableStructuresFromSQLDumpURL($fileURL) {
|
|
||||||
$context = stream_context_create(array('http' => array('header' => 'Accept: application/octet-stream')));
|
|
||||||
$fileContent = file_get_contents($fileURL, false, $context);
|
|
||||||
|
|
||||||
if ($fileContent === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$structure = array();
|
|
||||||
$queries = explode(";", $fileContent);
|
|
||||||
|
|
||||||
foreach ($queries as $query) {
|
|
||||||
$query = trim($query);
|
|
||||||
|
|
||||||
if (!empty($query)) {
|
|
||||||
if (preg_match("/^CREATE TABLE `(.*)` \((.*)\)$/s", $query, $matches)) {
|
|
||||||
$tableName = $matches[1];
|
|
||||||
$tableStructure = $matches[2];
|
|
||||||
$structure[$tableName] = array('structure' => $tableStructure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $structure;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to fetch the database structure from the MySQL server
|
|
||||||
function fetchDatabaseStructureFromServer() {
|
|
||||||
|
|
||||||
global $mysqli;
|
|
||||||
|
|
||||||
$tables = array();
|
|
||||||
|
|
||||||
// Fetch table names
|
|
||||||
$result = $mysqli->query("SHOW TABLES");
|
|
||||||
|
|
||||||
if ($result->num_rows > 0) {
|
|
||||||
while ($row = $result->fetch_row()) {
|
|
||||||
$tableName = $row[0];
|
|
||||||
$tables[$tableName] = array();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch table structures
|
// Section: SSL Checks
|
||||||
foreach ($tables as $tableName => &$table) {
|
$sslChecks = [];
|
||||||
$result = $mysqli->query("SHOW CREATE TABLE `$tableName`");
|
|
||||||
|
|
||||||
if ($result->num_rows > 0) {
|
// Check if accessing via HTTPS
|
||||||
$row = $result->fetch_row();
|
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443;
|
||||||
$table['structure'] = $row[1];
|
$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 = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $tables;
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//function to get current crontab and return it as an array
|
// Remove trailing comma if present
|
||||||
function get_crontab() {
|
$line = rtrim($line, ',');
|
||||||
$crontab = shell_exec('crontab -l');
|
|
||||||
$crontab = explode(PHP_EOL, $crontab);
|
// Match column definition
|
||||||
return $crontab;
|
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] . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
// URL to the SQL dump file
|
$columns[$colName] = $colType;
|
||||||
$fileURL = "https://raw.githubusercontent.com/itflow-org/itflow/master/db.sql";
|
}
|
||||||
|
}
|
||||||
// Load the desired table structures from the SQL dump file URL
|
$sqlTables[$tableName] = $columns;
|
||||||
$desiredStructure = loadTableStructuresFromSQLDumpURL($fileURL);
|
}
|
||||||
|
|
||||||
if ($desiredStructure === null) {
|
|
||||||
die("Failed to load the desired table structures from the SQL dump file URL.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the current database structure from the MySQL server
|
// Get current database table structures
|
||||||
$currentStructure = fetchDatabaseStructureFromServer();
|
$dbTables = [];
|
||||||
|
$tablesResult = $mysqli->query("SHOW TABLES");
|
||||||
if ($currentStructure === null) {
|
|
||||||
die("Failed to fetch the current database structure from the server.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare the structures and display the differences
|
|
||||||
$differences = arrayDiffRecursive($desiredStructure, $currentStructure);
|
|
||||||
|
|
||||||
//DB Stats
|
|
||||||
// Query to fetch the number of tables
|
|
||||||
$tablesQuery = "SHOW TABLES";
|
|
||||||
$tablesResult = $mysqli->query($tablesQuery);
|
|
||||||
|
|
||||||
$numTables = $tablesResult->num_rows;
|
|
||||||
$numFields = 0;
|
|
||||||
$numRows = 0;
|
|
||||||
|
|
||||||
// Loop through each table
|
|
||||||
while ($row = $tablesResult->fetch_row()) {
|
while ($row = $tablesResult->fetch_row()) {
|
||||||
$tableName = $row[0];
|
$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();
|
||||||
|
|
||||||
// Query to fetch the number of fields
|
// Compare the structures
|
||||||
$fieldsQuery = "DESCRIBE `$tableName`";
|
foreach ($sqlTables as $tableName => $sqlColumns) {
|
||||||
$fieldsResult = $mysqli->query($fieldsQuery);
|
if (!isset($dbTables[$tableName])) {
|
||||||
|
$dbComparison[] = [
|
||||||
|
'name' => "Table `$tableName` missing in database",
|
||||||
|
'status' => 'Missing Table',
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the query was successful
|
// Compare columns
|
||||||
if ($fieldsResult) {
|
$dbColumns = $dbTables[$tableName];
|
||||||
$numFields += $fieldsResult->num_rows;
|
foreach ($sqlColumns as $colName => $colType) {
|
||||||
|
if (!isset($dbColumns[$colName])) {
|
||||||
// Query to fetch the number of rows
|
$dbComparison[] = [
|
||||||
$rowsQuery = "SELECT COUNT(*) FROM `$tableName`";
|
'name' => "Column `$colName` missing in table `$tableName`",
|
||||||
$rowsResult = $mysqli->query($rowsQuery);
|
'status' => 'Missing Column',
|
||||||
|
];
|
||||||
// Check if the query was successful
|
|
||||||
if ($rowsResult) {
|
|
||||||
$numRows += $rowsResult->fetch_row()[0];
|
|
||||||
} else {
|
} else {
|
||||||
echo "Error executing query: " . $mysqli->error;
|
// 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 {
|
} else {
|
||||||
echo "Error executing query: " . $mysqli->error;
|
$dbComparison[] = [
|
||||||
}
|
'name' => 'db.sql file not found',
|
||||||
|
'status' => 'File Missing',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get loaded PHP modules
|
$mysqli->close();
|
||||||
$loadedModules = get_loaded_extensions();
|
|
||||||
|
|
||||||
//Get Server Info / Service versions
|
|
||||||
$phpVersion = phpversion();
|
|
||||||
$databaseInfo = mysqli_get_server_info($mysqli) . " / " . $mysqli->server_version;
|
|
||||||
$operatingSystem = php_uname();
|
|
||||||
$webServer = $_SERVER['SERVER_SOFTWARE'];
|
|
||||||
$errorLog = ini_get('error_log') ?: "Debian/Ubuntu default is usually /var/log/apache2/error.log";
|
|
||||||
$updates = fetchUpdates();
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="card card-dark">
|
<div class="card card-dark">
|
||||||
|
|
@ -205,128 +517,220 @@ $updates = fetchUpdates();
|
||||||
<li><a class="text-danger text-bold">Caution:</a> Be careful when sharing the full debug output - it contains your PHP session variables/cookies ("PHPSESSID") which could allow anyone to login to your ITFlow instance</li>
|
<li><a class="text-danger text-bold">Caution:</a> Be careful when sharing the full debug output - it contains your PHP session variables/cookies ("PHPSESSID") which could allow anyone to login to your ITFlow instance</li>
|
||||||
<li>Note: Sometimes you might need to gather <a href="https://docs.itflow.org/gathering_logs#error_logs">PHP error logs</a> as well</li>
|
<li>Note: Sometimes you might need to gather <a href="https://docs.itflow.org/gathering_logs#error_logs">PHP error logs</a> as well</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
|
||||||
|
|
||||||
<h3>Server Info</h3>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
echo "PHP version: " . $phpVersion . "<br>";
|
|
||||||
echo "Database Version: " . $databaseInfo . "<br>";
|
|
||||||
echo "Operating System: " . $operatingSystem . "<br>";
|
|
||||||
echo "Web Server: " . $webServer . "<br>";
|
|
||||||
echo "Apache/PHP Error Log: " . $errorLog
|
|
||||||
?>
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<h3>File System</h3>
|
<!-- System Information Table -->
|
||||||
<?php
|
<h3>System Information</h3>
|
||||||
$result = countFilesInDirectory($folderPath);
|
<table class="table table-sm table-bordered">
|
||||||
|
<tbody>
|
||||||
$totalFiles = $result['count'];
|
<?php foreach ($systemInfo as $info): ?>
|
||||||
$totalSizeMB = round($result['size'] / (1024 * 1024), 2);
|
|
||||||
|
|
||||||
echo "Total number of files in $folderPath and its subdirectories: " . $totalFiles . "<br>";
|
|
||||||
echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB";
|
|
||||||
?>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<h3>ITFlow app</h3>
|
|
||||||
<?php
|
|
||||||
echo "App Version: " . $updates->current_version . "<br>";
|
|
||||||
echo "Cron enabled: " . $config_enable_cron . "<br>";
|
|
||||||
echo "App Timezone: " . $config_timezone;
|
|
||||||
?>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Database Structure Check</h3>
|
|
||||||
|
|
||||||
<h4>Database stats</h4>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
echo "Number of tables: " . $numTables . "<br>";
|
|
||||||
echo "Total number of fields: " . $numFields . "<br>";
|
|
||||||
echo "Total number of rows: " . $numRows . "<br>";
|
|
||||||
echo "Current Database Version: " . CURRENT_DATABASE_VERSION . "<br>";
|
|
||||||
?>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h4>Table Stats</h4>
|
|
||||||
<?php
|
|
||||||
// Fetch all table names from the database
|
|
||||||
$tables = array();
|
|
||||||
$result = mysqli_query($mysqli, "SHOW TABLES");
|
|
||||||
while ($row = mysqli_fetch_array($result)) {
|
|
||||||
$tables[] = $row[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate an HTML table to display the results
|
|
||||||
?>
|
|
||||||
<table class="table table-sm">
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>Table Name</th>
|
<td><?= htmlspecialchars($info['name']); ?></td>
|
||||||
<th>Number of Fields</th>
|
<td><?= htmlspecialchars($info['value']); ?></td>
|
||||||
<th>Number of Rows</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
<?php
|
</tbody>
|
||||||
|
|
||||||
foreach ($tables as $table) {
|
|
||||||
// Count the number of fields and rows for each table
|
|
||||||
$columns_result = mysqli_query($mysqli, "SHOW COLUMNS FROM `$table`");
|
|
||||||
$columns = mysqli_num_rows($columns_result);
|
|
||||||
|
|
||||||
$rows_result = mysqli_query($mysqli, "SELECT COUNT(*) FROM `$table`");
|
|
||||||
$rows = mysqli_fetch_array($rows_result)[0];
|
|
||||||
?>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><?php echo $table; ?></td>
|
|
||||||
<td><?php echo $columns; ?></td>
|
|
||||||
<td><?php echo $rows; ?></td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<hr>
|
<!-- PHP Extensions and Configuration Table -->
|
||||||
|
<h3 class="mt-3">PHP Extensions and Configuration</h3>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<!-- PHP Extensions Section -->
|
||||||
|
<thead>
|
||||||
|
<tr class="table-secondary">
|
||||||
|
<th colspan="3">PHP Extensions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($phpExtensions as $check): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($check['name']); ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<?php if ($check['passed']): ?>
|
||||||
|
<i class="fas fa-check" style="color:green"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-times" style="color:red"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($check['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
<!-- PHP Configuration Section -->
|
||||||
|
<thead>
|
||||||
|
<tr class="table-secondary">
|
||||||
|
<th colspan="3">PHP Configuration</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($phpConfig as $check): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($check['name']); ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<?php if ($check['passed']): ?>
|
||||||
|
<i class="fas fa-check" style="color:green"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-times" style="color:red"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($check['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
<thead>
|
||||||
|
<tr class="table-secondary">
|
||||||
|
<th colspan="3">Shell Commands</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($shellCommands as $check): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($check['name']); ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<?php if ($check['passed']): ?>
|
||||||
|
<i class="fas fa-check" style="color:green"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-times" style="color:red"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($check['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
<thead>
|
||||||
|
<tr class="table-secondary">
|
||||||
|
<th colspan="3">SSL Checks</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($sslChecks as $check): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($check['name']); ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<?php if ($check['passed']): ?>
|
||||||
|
<i class="fas fa-check" style="color:green"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-times" style="color:red"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($check['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
<thead>
|
||||||
|
<tr class="table-secondary">
|
||||||
|
<th colspan="3">Domain Checks</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($domainChecks as $check): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($check['name']); ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<?php if ($check['passed']): ?>
|
||||||
|
<i class="fas fa-check" style="color:green"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-times" style="color:red"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($check['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
<h3>PHP Modules Installed</h3>
|
<!-- File Permissions Table -->
|
||||||
|
<thead>
|
||||||
|
<tr class="table-secondary">
|
||||||
|
<th colspan="3">File Permissions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($filePermissions as $check): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($check['name']); ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<?php if ($check['passed']): ?>
|
||||||
|
<i class="fas fa-check" style="color:green"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-times" style="color:red"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($check['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
<?php
|
|
||||||
foreach ($loadedModules as $module) {
|
|
||||||
echo $module . "<br>";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>PHP Info</h3>
|
<!-- Database Structure Comparison Table -->
|
||||||
<?php
|
<h3 class="mt-3">Database Structure Comparison</h3>
|
||||||
//Output phpinfo, but in a way that doesnt mess up the page
|
<table class="table table-sm table-bordered">
|
||||||
ob_start();
|
<tbody>
|
||||||
phpinfo();
|
<?php if (!empty($dbComparison)): ?>
|
||||||
$phpinfo = ob_get_contents();
|
<?php foreach ($dbComparison as $issue): ?>
|
||||||
ob_end_clean();
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($issue['name']); ?></td>
|
||||||
|
<td colspan="2"><?= htmlspecialchars($issue['status']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3">No discrepancies found between the database and db.sql file.</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
//Remove everything before the body tag
|
<!-- Uploads Directory Stats Table -->
|
||||||
$phpinfo = preg_replace('%^.*<body>(.*)</body>.*$%ms', '$1', $phpinfo);
|
<h3 class="mt-3">Uploads Directory Stats</h3>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($uploadsStats as $stat): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($stat['name']); ?></td>
|
||||||
|
<td colspan="2"><?= htmlspecialchars($stat['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
//Remove everything after the body tag
|
<!-- Database Stats Table -->
|
||||||
$phpinfo = preg_replace('%^(.*)</body>.*$%ms', '$1', $phpinfo);
|
<h3 class="mt-3">Database Stats</h3>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($databaseStats as $stat): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($stat['name']); ?></td>
|
||||||
|
<td colspan="2"><?= htmlspecialchars($stat['value']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
//Remove the body tag itself
|
<!-- Table Stats Table -->
|
||||||
$phpinfo = preg_replace('%^<body>(.*)$%ms', '$1', $phpinfo);
|
<h3 class="mt-3">Table Stats</h3>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Table Name</th>
|
||||||
|
<th>Fields / Rows</th>
|
||||||
|
<th>Size (MB)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($tableDetails as $table): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($table['name']); ?></td>
|
||||||
|
<td><?= htmlspecialchars("Fields: {$table['fields']}, Rows: {$table['rows']}"); ?></td>
|
||||||
|
<td><?= htmlspecialchars($table['size'] . ' MB'); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
//Output the result
|
|
||||||
echo $phpinfo;
|
|
||||||
?>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,335 @@
|
||||||
|
<?php
|
||||||
|
require_once "inc_all_admin.php";
|
||||||
|
|
||||||
|
require_once "database_version.php";
|
||||||
|
|
||||||
|
require_once "config.php";
|
||||||
|
|
||||||
|
$folderPath = 'uploads';
|
||||||
|
|
||||||
|
function countFilesInDirectory($dir) {
|
||||||
|
$count = 0;
|
||||||
|
$size = 0;
|
||||||
|
$files = scandir($dir);
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if ($file === '.' || $file === '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filePath = $dir . '/' . $file;
|
||||||
|
|
||||||
|
if (is_file($filePath)) {
|
||||||
|
$count++;
|
||||||
|
$size += filesize($filePath);
|
||||||
|
} elseif (is_dir($filePath)) {
|
||||||
|
$result = countFilesInDirectory($filePath);
|
||||||
|
$count += $result['count'];
|
||||||
|
$size += $result['size'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'count' => $count,
|
||||||
|
'size' => $size
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to compare two arrays recursively and return the differences
|
||||||
|
function arrayDiffRecursive($array1, $array2) {
|
||||||
|
$diff = array();
|
||||||
|
|
||||||
|
foreach ($array1 as $key => $value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (!isset($array2[$key]) || !is_array($array2[$key])) {
|
||||||
|
$diff[$key] = $value;
|
||||||
|
} else {
|
||||||
|
$recursiveDiff = arrayDiffRecursive($value, $array2[$key]);
|
||||||
|
if (!empty($recursiveDiff)) {
|
||||||
|
$diff[$key] = $recursiveDiff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isset($array2[$key]) || $array2[$key] !== $value) {
|
||||||
|
$diff[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to load the table structures from an SQL dump file URL
|
||||||
|
function loadTableStructuresFromSQLDumpURL($fileURL) {
|
||||||
|
$context = stream_context_create(array('http' => array('header' => 'Accept: application/octet-stream')));
|
||||||
|
$fileContent = file_get_contents($fileURL, false, $context);
|
||||||
|
|
||||||
|
if ($fileContent === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$structure = array();
|
||||||
|
$queries = explode(";", $fileContent);
|
||||||
|
|
||||||
|
foreach ($queries as $query) {
|
||||||
|
$query = trim($query);
|
||||||
|
|
||||||
|
if (!empty($query)) {
|
||||||
|
if (preg_match("/^CREATE TABLE `(.*)` \((.*)\)$/s", $query, $matches)) {
|
||||||
|
$tableName = $matches[1];
|
||||||
|
$tableStructure = $matches[2];
|
||||||
|
$structure[$tableName] = array('structure' => $tableStructure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to fetch the database structure from the MySQL server
|
||||||
|
function fetchDatabaseStructureFromServer() {
|
||||||
|
|
||||||
|
global $mysqli;
|
||||||
|
|
||||||
|
$tables = array();
|
||||||
|
|
||||||
|
// Fetch table names
|
||||||
|
$result = $mysqli->query("SHOW TABLES");
|
||||||
|
|
||||||
|
if ($result->num_rows > 0) {
|
||||||
|
while ($row = $result->fetch_row()) {
|
||||||
|
$tableName = $row[0];
|
||||||
|
$tables[$tableName] = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch table structures
|
||||||
|
foreach ($tables as $tableName => &$table) {
|
||||||
|
$result = $mysqli->query("SHOW CREATE TABLE `$tableName`");
|
||||||
|
|
||||||
|
if ($result->num_rows > 0) {
|
||||||
|
$row = $result->fetch_row();
|
||||||
|
$table['structure'] = $row[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
//function to get current crontab and return it as an array
|
||||||
|
function get_crontab() {
|
||||||
|
$crontab = shell_exec('crontab -l');
|
||||||
|
$crontab = explode(PHP_EOL, $crontab);
|
||||||
|
return $crontab;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL to the SQL dump file
|
||||||
|
$fileURL = "https://raw.githubusercontent.com/itflow-org/itflow/master/db.sql";
|
||||||
|
|
||||||
|
// Load the desired table structures from the SQL dump file URL
|
||||||
|
$desiredStructure = loadTableStructuresFromSQLDumpURL($fileURL);
|
||||||
|
|
||||||
|
if ($desiredStructure === null) {
|
||||||
|
die("Failed to load the desired table structures from the SQL dump file URL.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the current database structure from the MySQL server
|
||||||
|
$currentStructure = fetchDatabaseStructureFromServer();
|
||||||
|
|
||||||
|
if ($currentStructure === null) {
|
||||||
|
die("Failed to fetch the current database structure from the server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the structures and display the differences
|
||||||
|
$differences = arrayDiffRecursive($desiredStructure, $currentStructure);
|
||||||
|
|
||||||
|
//DB Stats
|
||||||
|
// Query to fetch the number of tables
|
||||||
|
$tablesQuery = "SHOW TABLES";
|
||||||
|
$tablesResult = $mysqli->query($tablesQuery);
|
||||||
|
|
||||||
|
$numTables = $tablesResult->num_rows;
|
||||||
|
$numFields = 0;
|
||||||
|
$numRows = 0;
|
||||||
|
|
||||||
|
// Loop through each table
|
||||||
|
while ($row = $tablesResult->fetch_row()) {
|
||||||
|
$tableName = $row[0];
|
||||||
|
|
||||||
|
// Query to fetch the number of fields
|
||||||
|
$fieldsQuery = "DESCRIBE `$tableName`";
|
||||||
|
$fieldsResult = $mysqli->query($fieldsQuery);
|
||||||
|
|
||||||
|
// Check if the query was successful
|
||||||
|
if ($fieldsResult) {
|
||||||
|
$numFields += $fieldsResult->num_rows;
|
||||||
|
|
||||||
|
// Query to fetch the number of rows
|
||||||
|
$rowsQuery = "SELECT COUNT(*) FROM `$tableName`";
|
||||||
|
$rowsResult = $mysqli->query($rowsQuery);
|
||||||
|
|
||||||
|
// Check if the query was successful
|
||||||
|
if ($rowsResult) {
|
||||||
|
$numRows += $rowsResult->fetch_row()[0];
|
||||||
|
} else {
|
||||||
|
echo "Error executing query: " . $mysqli->error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo "Error executing query: " . $mysqli->error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get loaded PHP modules
|
||||||
|
$loadedModules = get_loaded_extensions();
|
||||||
|
|
||||||
|
//Get Server Info / Service versions
|
||||||
|
$phpVersion = phpversion();
|
||||||
|
$databaseInfo = mysqli_get_server_info($mysqli) . " / " . $mysqli->server_version;
|
||||||
|
$operatingSystem = php_uname();
|
||||||
|
$webServer = $_SERVER['SERVER_SOFTWARE'];
|
||||||
|
$errorLog = ini_get('error_log') ?: "Debian/Ubuntu default is usually /var/log/apache2/error.log";
|
||||||
|
$updates = fetchUpdates();
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card card-dark">
|
||||||
|
<div class="card-header py-3">
|
||||||
|
<h3 class="card-title"><i class="fas fa-fw fa-bug mr-2"></i>Debug</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<h2>Debugging</h2>
|
||||||
|
<ul>
|
||||||
|
<li>If you are experiencing a problem with ITFlow you may be directed to this page to gather server/app info.</li>
|
||||||
|
<li>When creating forum posts / support requests ensure you share the information under <i>Server Info</i>, <i>ITFlow app</i> and <i>Database stats</i>.</li>
|
||||||
|
<li><a class="text-danger text-bold">Caution:</a> Be careful when sharing the full debug output - it contains your PHP session variables/cookies ("PHPSESSID") which could allow anyone to login to your ITFlow instance</li>
|
||||||
|
<li>Note: Sometimes you might need to gather <a href="https://docs.itflow.org/gathering_logs#error_logs">PHP error logs</a> as well</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h3>Server Info</h3>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
echo "PHP version: " . $phpVersion . "<br>";
|
||||||
|
echo "Database Version: " . $databaseInfo . "<br>";
|
||||||
|
echo "Operating System: " . $operatingSystem . "<br>";
|
||||||
|
echo "Web Server: " . $webServer . "<br>";
|
||||||
|
echo "Apache/PHP Error Log: " . $errorLog
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3>File System</h3>
|
||||||
|
<?php
|
||||||
|
$result = countFilesInDirectory($folderPath);
|
||||||
|
|
||||||
|
$totalFiles = $result['count'];
|
||||||
|
$totalSizeMB = round($result['size'] / (1024 * 1024), 2);
|
||||||
|
|
||||||
|
echo "Total number of files in $folderPath and its subdirectories: " . $totalFiles . "<br>";
|
||||||
|
echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB";
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h3>ITFlow app</h3>
|
||||||
|
<?php
|
||||||
|
echo "App Version: " . $updates->current_version . "<br>";
|
||||||
|
echo "Cron enabled: " . $config_enable_cron . "<br>";
|
||||||
|
echo "App Timezone: " . $config_timezone;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3>Database Structure Check</h3>
|
||||||
|
|
||||||
|
<h4>Database stats</h4>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
echo "Number of tables: " . $numTables . "<br>";
|
||||||
|
echo "Total number of fields: " . $numFields . "<br>";
|
||||||
|
echo "Total number of rows: " . $numRows . "<br>";
|
||||||
|
echo "Current Database Version: " . CURRENT_DATABASE_VERSION . "<br>";
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4>Table Stats</h4>
|
||||||
|
<?php
|
||||||
|
// Fetch all table names from the database
|
||||||
|
$tables = array();
|
||||||
|
$result = mysqli_query($mysqli, "SHOW TABLES");
|
||||||
|
while ($row = mysqli_fetch_array($result)) {
|
||||||
|
$tables[] = $row[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate an HTML table to display the results
|
||||||
|
?>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<tr>
|
||||||
|
<th>Table Name</th>
|
||||||
|
<th>Number of Fields</th>
|
||||||
|
<th>Number of Rows</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
// Count the number of fields and rows for each table
|
||||||
|
$columns_result = mysqli_query($mysqli, "SHOW COLUMNS FROM `$table`");
|
||||||
|
$columns = mysqli_num_rows($columns_result);
|
||||||
|
|
||||||
|
$rows_result = mysqli_query($mysqli, "SELECT COUNT(*) FROM `$table`");
|
||||||
|
$rows = mysqli_fetch_array($rows_result)[0];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><?php echo $table; ?></td>
|
||||||
|
<td><?php echo $columns; ?></td>
|
||||||
|
<td><?php echo $rows; ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3>PHP Modules Installed</h3>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
foreach ($loadedModules as $module) {
|
||||||
|
echo $module . "<br>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3>PHP Info</h3>
|
||||||
|
<?php
|
||||||
|
//Output phpinfo, but in a way that doesnt mess up the page
|
||||||
|
ob_start();
|
||||||
|
phpinfo();
|
||||||
|
$phpinfo = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
//Remove everything before the body tag
|
||||||
|
$phpinfo = preg_replace('%^.*<body>(.*)</body>.*$%ms', '$1', $phpinfo);
|
||||||
|
|
||||||
|
//Remove everything after the body tag
|
||||||
|
$phpinfo = preg_replace('%^(.*)</body>.*$%ms', '$1', $phpinfo);
|
||||||
|
|
||||||
|
//Remove the body tag itself
|
||||||
|
$phpinfo = preg_replace('%^<body>(.*)$%ms', '$1', $phpinfo);
|
||||||
|
|
||||||
|
//Output the result
|
||||||
|
echo $phpinfo;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once "footer.php";
|
||||||
|
|
||||||
Loading…
Reference in New Issue