From 351bb484a7bb203a482be2c13889fcd35977ec7d Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 5 Nov 2024 17:36:50 -0500 Subject: [PATCH] Reworked the entire debugger, only grather nessesary info and database comparison to existing and db.sql works now --- admin_debug.php | 976 +++++++++++++++++++++++++++++------------ admin_legacy_debug.php | 335 ++++++++++++++ 2 files changed, 1025 insertions(+), 286 deletions(-) create mode 100644 admin_legacy_debug.php diff --git a/admin_debug.php b/admin_debug.php index 61591900..fc6d659a 100644 --- a/admin_debug.php +++ b/admin_debug.php @@ -5,330 +5,734 @@ require_once "database_version.php"; require_once "config.php"; -$folderPath = 'uploads'; +$checks = []; -function countFilesInDirectory($dir) { - $count = 0; - $size = 0; - $files = scandir($dir); +// Section: System Information +$systemInfo = []; - foreach ($files as $file) { - if ($file === '.' || $file === '..') { - continue; - } +// Operating System and Version +$os = php_uname(); +$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)) { - $count++; - $size += filesize($filePath); - } elseif (is_dir($filePath)) { - $result = countFilesInDirectory($filePath); - $count += $result['count']; - $size += $result['size']; - } - } +// Kernel and Version +$kernelVersion = php_uname('r'); +$systemInfo[] = [ + 'name' => 'Kernel Version', + 'value' => $kernelVersion, +]; - return [ - 'count' => $count, - 'size' => $size +// 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', ]; } -// Function to compare two arrays recursively and return the differences -function arrayDiffRecursive($array1, $array2) { - $diff = array(); +// Section: PHP Configuration +$phpConfig = []; - 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; +// 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; } } - } else { - if (!isset($array2[$key]) || $array2[$key] !== $value) { - $diff[$key] = $value; + $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', + ]; } } } - 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); - } + // 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', + ]; } } - - return $structure; +} else { + $dbComparison[] = [ + 'name' => 'db.sql file not found', + 'status' => 'File Missing', + ]; } -// 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(); - +$mysqli->close(); ?> -
-
-

Debug

-
-
+
+
+

Debug

+
+
-

Debugging

-
    -
  • If you are experiencing a problem with ITFlow you may be directed to this page to gather server/app info.
  • -
  • When creating forum posts / support requests ensure you share the information under Server Info, ITFlow app and Database stats.
  • -
  • Caution: 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
  • -
  • Note: Sometimes you might need to gather PHP error logs as well
  • -
-
+

Debugging

+
    +
  • If you are experiencing a problem with ITFlow you may be directed to this page to gather server/app info.
  • +
  • When creating forum posts / support requests ensure you share the information under Server Info, ITFlow app and Database stats.
  • +
  • Caution: 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
  • +
  • Note: Sometimes you might need to gather PHP error logs as well
  • +
+
-

Server Info

+ +

System Information

+ + + + + + + + + +
- "; - echo "Database Version: " . $databaseInfo . "
"; - echo "Operating System: " . $operatingSystem . "
"; - echo "Web Server: " . $webServer . "
"; - echo "Apache/PHP Error Log: " . $errorLog - ?> + +

PHP Extensions and Configuration

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

File System

- +

Database Structure Comparison

+ + + + + + + + + + + + + + + +
No discrepancies found between the database and db.sql file.
- echo "Total number of files in $folderPath and its subdirectories: " . $totalFiles . "
"; - echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB"; - ?> + +

Uploads Directory Stats

+ + + + + + + + + +
-
-

ITFlow app

- current_version . "
"; - echo "Cron enabled: " . $config_enable_cron . "
"; - echo "App Timezone: " . $config_timezone; - ?> + +

Database Stats

+ + + + + + + + + +
-
- -

Database Structure Check

- -

Database stats

- - "; - echo "Total number of fields: " . $numFields . "
"; - echo "Total number of rows: " . $numRows . "
"; - echo "Current Database Version: " . CURRENT_DATABASE_VERSION . "
"; - ?> - -
- -

Table Stats

- - + +

Table Stats

+
+ - - + + - - - + + + - - - + + + - -
Table NameNumber of FieldsNumber of RowsFields / RowsSize (MB)
+ + + -
- -

PHP Modules Installed

- - "; - } - ?> - -
- -

PHP Info

- (.*).*$%ms', '$1', $phpinfo); - - //Remove everything after the body tag - $phpinfo = preg_replace('%^(.*).*$%ms', '$1', $phpinfo); - - //Remove the body tag itself - $phpinfo = preg_replace('%^(.*)$%ms', '$1', $phpinfo); - - //Output the result - echo $phpinfo; - ?> - -
-
+
+ $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(); + +?> + +
+
+

Debug

+
+
+ +

Debugging

+
    +
  • If you are experiencing a problem with ITFlow you may be directed to this page to gather server/app info.
  • +
  • When creating forum posts / support requests ensure you share the information under Server Info, ITFlow app and Database stats.
  • +
  • Caution: 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
  • +
  • Note: Sometimes you might need to gather PHP error logs as well
  • +
+
+ +

Server Info

+ + "; + echo "Database Version: " . $databaseInfo . "
"; + echo "Operating System: " . $operatingSystem . "
"; + echo "Web Server: " . $webServer . "
"; + echo "Apache/PHP Error Log: " . $errorLog + ?> + +
+ +

File System

+ "; + echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB"; + ?> + +
+

ITFlow app

+ current_version . "
"; + echo "Cron enabled: " . $config_enable_cron . "
"; + echo "App Timezone: " . $config_timezone; + ?> + +
+ +

Database Structure Check

+ +

Database stats

+ + "; + echo "Total number of fields: " . $numFields . "
"; + echo "Total number of rows: " . $numRows . "
"; + echo "Current Database Version: " . CURRENT_DATABASE_VERSION . "
"; + ?> + +
+ +

Table Stats

+ + + + + + + + + + + + + + + + +
Table NameNumber of FieldsNumber of Rows
+ +
+ +

PHP Modules Installed

+ + "; + } + ?> + +
+ +

PHP Info

+ (.*).*$%ms', '$1', $phpinfo); + + //Remove everything after the body tag + $phpinfo = preg_replace('%^(.*).*$%ms', '$1', $phpinfo); + + //Remove the body tag itself + $phpinfo = preg_replace('%^(.*)$%ms', '$1', $phpinfo); + + //Output the result + echo $phpinfo; + ?> + +
+
+
+ +