Debug - how ITFlow and the server under it are doing * (functions/system_health.php). What needs putting right comes first, each * with what to do and where; then the figures at a glance, every check by * section, the database (its size, biggest tables and how its structure * compares with db.sql) and the uploads folder. Copy for support puts it all * on the clipboard as plain text for a forum post or a support email, * without host names, paths or keys. */ require_once "includes/inc_all_admin.php"; require_once "../includes/database_version.php"; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/cron_jobs.php'; // the jobs' names $sections = healthChecks(); $summary = healthSummary($sections); $exact = !empty($_GET['exact']); // Count exactly - every table counted, rather than the database's estimate $database_stats = healthDatabaseTables($exact); $differences = healthStructureDifferences(); $uploads = healthUploads(); $report = healthReport($sections, $database_stats, $differences, $uploads); $levels = healthLevels(); // The figures along the top $cron = healthRow("SELECT config_cron_last_dispatch_at FROM settings WHERE company_id = 1"); $cron_heard = $cron['config_cron_last_dispatch_at'] ?? null; $cron_stale = !$cron_heard || time() - strtotime($cron_heard) >= 300; $last_backup = healthRow("SELECT backup_completed_at, backup_size FROM backups WHERE backup_status = 'Complete' ORDER BY backup_completed_at DESC LIMIT 1"); $errors_day = healthRow("SELECT COUNT(*) AS n FROM app_logs WHERE app_log_type = 'error' AND app_log_created_at > NOW() - INTERVAL 1 DAY"); try { $mail = mailQueueSummary(); } catch (Throwable $e) { $mail = null; } $db_behind = version_compare((string) LATEST_DATABASE_VERSION, (string) CURRENT_DATABASE_VERSION, '>'); $branch = gitCurrentBranch(); $commit = gitCurrentCommit(); $stats = [ ['label' => 'ITFlow', 'value' => APP_VERSION, 'sub' => escapeHtml($branch !== '' ? $branch . ($commit !== '' ? ' @ ' . substr($commit, 0, 7) : '') : 'Not a git checkout')], ['label' => 'Database', 'value' => CURRENT_DATABASE_VERSION, 'tone' => $db_behind ? 'danger' : '', 'url' => $db_behind ? 'update.php' : '', 'sub' => $db_behind ? 'Update to ' . escapeHtml(LATEST_DATABASE_VERSION) . ' waiting' : 'Up to date'], ['label' => 'PHP', 'value' => PHP_VERSION, 'sub' => escapeHtml(PHP_SAPI)], ['label' => 'Cron', 'value' => healthShortAgo($cron_heard), 'title' => $cron_heard ? 'Last ran ' . healthAgo($cron_heard) : '', 'tone' => $cron_stale ? 'danger' : '', 'url' => 'cron.php', 'sub' => $cron_stale ? 'Not running' : 'Running'], ['label' => 'Failed email', 'value' => $mail ? number_format($mail['failed_week']) : '-', 'tone' => $mail && $mail['failed_week'] ? 'warning' : '', 'url' => $mail && $mail['failed_week'] ? 'mail_queue.php?show=failed' : 'mail_queue.php', 'sub' => $mail ? 'This week · ' . number_format($mail['waiting']) . ' waiting' : 'Database update needed'], ['label' => 'Last backup', 'value' => $last_backup ? healthShortAgo($last_backup['backup_completed_at']) : 'None yet', 'url' => 'backup.php', 'tone' => !$last_backup || strtotime($last_backup['backup_completed_at']) < time() - 7 * 86400 ? 'warning' : '', 'sub' => $last_backup ? escapeHtml(formatBytes(intval($last_backup['backup_size']), 1)) : 'Take one now'], ['label' => 'Errors', 'value' => $errors_day ? number_format(intval($errors_day['n'])) : '-', 'tone' => !empty($errors_day['n']) ? 'warning' : '', 'url' => !empty($errors_day['n']) ? 'app_logs.php?view=error' : 'app_logs.php', 'sub' => 'In the last day'], ]; $problems = $summary['counts']['danger']; $warnings = $summary['counts']['warning']; $checked = array_sum($summary['counts']); $plural = function ($n, $one, $many) { return number_format($n) . ' ' . ($n === 1 ? $one : $many); }; // A link from a check - ITFlow's own pages here, the docs in a new tab $action_link = function (array $item, $class) { if ($item['url'] === '') { return ''; } $outside = preg_match('#^https?://#i', $item['url']); return '' . escapeHtml($item['action'] !== '' ? $item['action'] : 'Open') . ''; }; ?>
db.sql isn't here to compare with.
Every table and column matches db.sql - what a fresh install makes.
= $plural(count($differences), 'difference', 'differences') ?> from db.sql. Something missing usually means a database update didn't finish - Maintenance > Update. Extra tables and columns are usually left by older versions or a plugin, and do no harm.
| What | Where | db.sql | Here |
|---|---|---|---|
| = escapeHtml($difference['what']) ?> | = escapeHtml($difference['table'] . ($difference['column'] !== '' ? '.' . $difference['column'] : '')) ?> |
= escapeHtml($difference['expected']) ?> | = escapeHtml($difference['found']) ?> |
| Table | = $exact ? 'Rows' : 'Rows (about)' ?> | Size | |
|---|---|---|---|
| = escapeHtml($table) ?> | = number_format($table_stats['rows']) ?> | = escapeHtml(formatBytes($table_stats['bytes'], 1)) ?> |
Every table counted. Back to estimates Row counts are the database's own estimate, so a big install opens this page quickly. Count exactly - slower on a big install.
Nothing uploaded yet.
| Folder | Files | Size |
|---|---|---|
| = escapeHtml($folder) ?> | = number_format($folder_stats['files']) ?> | = escapeHtml(formatBytes($folder_stats['bytes'], 1)) ?> |
There are a lot of files - counting stopped after a few seconds, so these are at least what is there.
Versions, what needs looking at, and the size of things - without host names, paths, addresses or keys. Read it before you post it.
For a problem this page doesn't show, the web server's and PHP's own error logs say more - how to find them.