Files
JobcardSystem/bin/healthcheck.php
T

131 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
require_once dirname(__DIR__) . '/config/bootstrap.php';
/**
* Deployment checks are kept as small functions so they can be tested without
* loading application state or requiring a live database.
*
* @return array<string, bool>
*/
function deployment_check_extensions(array $required, ?callable $loader = null): array
{
$loader ??= static fn(string $extension): bool => extension_loaded($extension);
$result = [];
foreach ($required as $extension) {
$result[(string)$extension] = (bool)$loader((string)$extension);
}
return $result;
}
/**
* @return array<string, bool>
*/
function deployment_check_environment(array $required, ?callable $reader = null): array
{
$reader ??= static fn(string $name): mixed => getenv($name);
$result = [];
foreach ($required as $name) {
$value = $reader((string)$name);
$result[(string)$name] = $value !== false && $value !== null && trim((string)$value) !== '';
}
return $result;
}
/**
* @return array<string, bool>
*/
function deployment_check_directories(array $directories, ?callable $checker = null): array
{
$checker ??= static fn(string $directory): bool => is_dir($directory) && is_writable($directory);
$result = [];
foreach ($directories as $directory) {
$result[(string)$directory] = (bool)$checker((string)$directory);
}
return $result;
}
/**
* Return a deliberately value-free report suitable for CLI output or logging.
*
* @param array<string, bool> $checks
* @return array<string, string>
*/
function deployment_format_check_report(array $checks): array
{
$report = [];
foreach ($checks as $name => $passed) {
$report[$name] = $passed ? 'OK' : 'FAIL';
}
return $report;
}
function deployment_check_schema(PDO $pdo): bool
{
foreach (['roles', 'permissions', 'role_permissions', 'users', 'app_settings', 'clients', 'client_contacts', 'jobcard_sequences', 'technical_information', 'credentials', 'sla_agreements', 'jobcards', 'jobcard_assignments', 'jobcard_status_history', 'time_entries', 'attachments', 'notifications', 'audit_events'] as $table) {
$quoted = '`' . str_replace('`', '``', $table) . '`';
$pdo->query("SELECT 1 FROM {$quoted} LIMIT 1");
}
return true;
}
function deployment_print_check(string $label, bool $passed): void
{
printf("[%s] %s\n", $passed ? 'OK' : 'FAIL', $label);
}
function deployment_run_healthcheck(): int
{
$requiredExtensions = ['pdo_mysql', 'mbstring', 'openssl', 'sodium', 'json', 'fileinfo'];
$requiredEnvironment = [
'APP_ENV', 'APP_KEY', 'DB_HOST', 'DB_PORT', 'DB_DATABASE',
'DB_USERNAME', 'DB_PASSWORD', 'ADMIN_EMAIL', 'ADMIN_PASSWORD',
];
$runtimeDirectories = [
dirname(__DIR__) . '/storage',
dirname(__DIR__) . '/storage/logs',
dirname(__DIR__) . '/storage/uploads',
];
fwrite(STDOUT, "JOBcard deployment health check\n");
$allPassed = true;
foreach (deployment_format_check_report(deployment_check_extensions($requiredExtensions)) as $extension => $status) {
$passed = $status === 'OK';
deployment_print_check("PHP extension: {$extension}", $passed);
$allPassed = $allPassed && $passed;
}
foreach (deployment_format_check_report(deployment_check_environment($requiredEnvironment)) as $name => $status) {
$passed = $status === 'OK';
// Only the variable name and status are emitted; values are never printed.
deployment_print_check("Environment variable: {$name}", $passed);
$allPassed = $allPassed && $passed;
}
foreach (deployment_format_check_report(deployment_check_directories($runtimeDirectories)) as $directory => $status) {
$passed = $status === 'OK';
deployment_print_check("Writable runtime directory: {$directory}", $passed);
$allPassed = $allPassed && $passed;
}
try {
require_once dirname(__DIR__) . '/app/Domain/Credential/TechnicalInformation.php';
require_once dirname(__DIR__) . '/app/Domain/Credential/CredentialVault.php';
new \App\Domain\Credential\CredentialVault((string)getenv('APP_KEY'));
require_once dirname(__DIR__) . '/config/bootstrap.php';
deployment_check_schema(db());
deployment_print_check('Database connection and schema: core tables available', true);
} catch (Throwable) {
// Database exception text can contain infrastructure details; keep the check output safe.
deployment_print_check('Database connection and schema: roles table available', false);
$allPassed = false;
}
fwrite(STDOUT, $allPassed ? "Health check passed.\n" : "Health check failed.\n");
return $allPassed ? 0 : 1;
}
if (realpath($_SERVER['SCRIPT_FILENAME'] ?? '') === __FILE__) {
exit(deployment_run_healthcheck());
}