false, 'reason' => 'Windows-Server werden nicht unterstützt (Crontab ist ein Unix/Linux-Mechanismus).']; } $disabled = array_map('trim', explode(',', (string) ini_get('disable_functions'))); foreach (['proc_open', 'shell_exec'] as $fn) { if (!function_exists($fn) || in_array($fn, $disabled, true)) { return ['available' => false, 'reason' => "PHP-Funktion \"$fn\" ist auf diesem Server gesperrt (typisch für Shared-Hosting)."]; } } $out = @shell_exec('crontab -l 2>&1'); if ($out === null) { return ['available' => false, 'reason' => 'Der Befehl "crontab" konnte nicht ausgeführt werden.']; } // "no crontab for " ist der normale Zustand, wenn noch keine Crontab existiert – das ist OK. if (stripos($out, 'not found') !== false || stripos($out, 'command not found') !== false) { return ['available' => false, 'reason' => 'Das Programm "crontab" ist auf diesem Server nicht installiert.']; } if (stripos($out, 'permission denied') !== false) { return ['available' => false, 'reason' => 'Der Web-Server-Benutzer hat keine Berechtigung für crontab.']; } return ['available' => true, 'reason' => '']; } /** Versucht, den echten CLI-PHP-Pfad zu ermitteln (PHP_BINARY zeigt unter Apache/FPM auf den falschen Binary). */ function detect_php_cli_binary(): string { $which = trim((string) @shell_exec('command -v php 2>/dev/null')); if ($which !== '' && is_executable($which)) { return $which; } foreach (['/usr/bin/php', '/usr/local/bin/php', '/opt/php/bin/php'] as $candidate) { if (is_executable($candidate)) { return $candidate; } } return 'php'; // Fallback: hoffen, dass PATH im Cron-Kontext passt } /** Baut den verwalteten DeskHub-Block mit den Job-Zeilen (fest hinterlegte Kommandos, keine Nutzereingabe). */ function crontab_marker_block(): string { $php = detect_php_cli_binary(); $root = realpath(__DIR__ . '/..'); $lines = [ DESKHUB_CRON_MARKER_START, "*/5 * * * * $php $root/cron/fetch_emails.php >> $root/cron/fetch_emails.log 2>&1", "* * * * * $php $root/cron/status_checks.php >> $root/cron/status_checks.log 2>&1", "* * * * * $php $root/cron/run_plugins.php >> $root/cron/run_plugins.log 2>&1", "*/15 * * * * $php $root/cron/check_sla.php >> $root/cron/check_sla.log 2>&1", "0 * * * * $php $root/cron/check_escalations.php >> $root/cron/check_escalations.log 2>&1", "0 6 * * * $php $root/cron/process_recurring.php >> $root/cron/process_recurring.log 2>&1", "0 2 * * * $php $root/cron/process_backups.php >> $root/cron/process_backups.log 2>&1", "0 3 * * * $php $root/cron/anonymize_data.php >> $root/cron/anonymize_data.log 2>&1", DESKHUB_CRON_MARKER_END, ]; return implode("\n", $lines); } function crontab_get_current(): string { $out = @shell_exec('crontab -l 2>/dev/null'); return $out !== null ? $out : ''; } function crontab_is_installed(): bool { return str_contains(crontab_get_current(), DESKHUB_CRON_MARKER_START); } /** Entfernt einen ggf. vorhandenen DeskHub-Block aus einem Crontab-Text (Hilfsfunktion für install+remove). */ function crontab_strip_marker_block(string $content): string { $pattern = '/^' . preg_quote(DESKHUB_CRON_MARKER_START, '/') . '.*?^' . preg_quote(DESKHUB_CRON_MARKER_END, '/') . '\n?/ms'; return preg_replace($pattern, '', $content) ?? $content; } /** Schreibt einen kompletten neuen Crontab-Inhalt für den aktuellen Benutzer. */ function crontab_write(string $content): array { $descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; $proc = @proc_open('crontab -', $descriptors, $pipes); if (!is_resource($proc)) { return ['ok' => false, 'error' => 'crontab-Prozess konnte nicht gestartet werden.']; } fwrite($pipes[0], $content); fclose($pipes[0]); $stdout = stream_get_contents($pipes[1]); fclose($pipes[1]); $stderr = stream_get_contents($pipes[2]); fclose($pipes[2]); $code = proc_close($proc); if ($code !== 0) { return ['ok' => false, 'error' => trim($stderr) ?: trim($stdout) ?: "crontab beendete mit Fehlercode $code"]; } return ['ok' => true, 'error' => '']; } /** Installiert/aktualisiert den DeskHub-Block in der Crontab des aktuellen Benutzers. */ function crontab_install(): array { $check = crontab_capability_check(); if (!$check['available']) { return ['ok' => false, 'error' => $check['reason']]; } $current = crontab_strip_marker_block(crontab_get_current()); $current = rtrim($current, "\n"); $new = ($current !== '' ? $current . "\n\n" : '') . crontab_marker_block() . "\n"; return crontab_write($new); } /** Entfernt den DeskHub-Block aus der Crontab, lässt alle anderen Einträge unangetastet. */ function crontab_uninstall(): array { $check = crontab_capability_check(); if (!$check['available']) { return ['ok' => false, 'error' => $check['reason']]; } $current = crontab_get_current(); if (!str_contains($current, DESKHUB_CRON_MARKER_START)) { return ['ok' => true, 'error' => '']; // war gar nicht installiert } $new = crontab_strip_marker_block($current); return crontab_write($new); }