Stand: SMTP-Test, Admin-Mail-Tab, Notifiable-Fix, Lazy-Quill
- Fix: Notifiable-Trait zum User-Model hinzugefuegt (behebt notify()-500er) - Installer: SMTP-Verbindungstest mit EsmtpTransport + Ueberspringen-Link - Admin: Neuer E-Mail-Tab mit SMTP-Konfiguration + Verbindungstest - Admin: Lazy Quill-Initialisierung (nur sichtbare Locale wird geladen) - Uebersetzungen: 17 neue Mail-Keys in allen 6 Sprachen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
416
public/check.php
Normal file
416
public/check.php
Normal file
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
/**
|
||||
* Eigenstaendige Server-Diagnose (kein Laravel noetig).
|
||||
* Aufruf: https://deine-domain.de/check.php
|
||||
*
|
||||
* WICHTIG: Diese Datei nach erfolgreicher Installation loeschen!
|
||||
*/
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
$basePath = __DIR__ . '/..';
|
||||
$results = [];
|
||||
|
||||
// ─── PHP ─────────────────────────────────────────────────────
|
||||
$results[] = [
|
||||
'group' => 'PHP',
|
||||
'name' => 'PHP-Version',
|
||||
'value' => PHP_VERSION,
|
||||
'ok' => version_compare(PHP_VERSION, '8.2.0', '>='),
|
||||
'hint' => 'Mindestens PHP 8.2 erforderlich.',
|
||||
];
|
||||
|
||||
$results[] = [
|
||||
'group' => 'PHP',
|
||||
'name' => 'Server-API (SAPI)',
|
||||
'value' => PHP_SAPI,
|
||||
'ok' => true,
|
||||
'hint' => '',
|
||||
];
|
||||
|
||||
$extensions = ['pdo', 'pdo_sqlite', 'mbstring', 'openssl', 'tokenizer', 'xml', 'ctype', 'fileinfo', 'dom', 'curl'];
|
||||
foreach ($extensions as $ext) {
|
||||
$results[] = [
|
||||
'group' => 'PHP-Extensions',
|
||||
'name' => $ext,
|
||||
'value' => extension_loaded($ext) ? 'Geladen' : 'Fehlt',
|
||||
'ok' => extension_loaded($ext),
|
||||
'hint' => $ext === 'pdo_sqlite' ? 'Nur fuer SQLite noetig' : '',
|
||||
];
|
||||
}
|
||||
|
||||
// Optional
|
||||
$results[] = [
|
||||
'group' => 'PHP-Extensions',
|
||||
'name' => 'pdo_mysql (optional)',
|
||||
'value' => extension_loaded('pdo_mysql') ? 'Geladen' : 'Fehlt',
|
||||
'ok' => true, // optional
|
||||
'hint' => 'Nur fuer MySQL noetig.',
|
||||
];
|
||||
|
||||
// ─── Dateisystem ─────────────────────────────────────────────
|
||||
$dirs = [
|
||||
'storage',
|
||||
'storage/app',
|
||||
'storage/framework',
|
||||
'storage/framework/cache',
|
||||
'storage/framework/cache/data',
|
||||
'storage/framework/sessions',
|
||||
'storage/framework/views',
|
||||
'storage/logs',
|
||||
'bootstrap/cache',
|
||||
'database',
|
||||
];
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
$full = $basePath . '/' . $dir;
|
||||
$exists = is_dir($full);
|
||||
$writable = $exists && is_writable($full);
|
||||
$perms = $exists ? substr(sprintf('%o', fileperms($full)), -4) : '-';
|
||||
$owner = $exists ? (function_exists('posix_getpwuid') ? posix_getpwuid(fileowner($full))['name'] ?? fileowner($full) : fileowner($full)) : '-';
|
||||
|
||||
$results[] = [
|
||||
'group' => 'Verzeichnisse',
|
||||
'name' => $dir . '/',
|
||||
'value' => ($exists ? 'Existiert' : 'FEHLT') . ' | ' . ($writable ? 'Beschreibbar' : 'NICHT beschreibbar') . ' | ' . $perms . ' | Owner: ' . $owner,
|
||||
'ok' => $writable,
|
||||
'hint' => !$writable ? 'Berechtigungen auf 775 setzen' : '',
|
||||
];
|
||||
}
|
||||
|
||||
// ─── Dateien ─────────────────────────────────────────────────
|
||||
$files = [
|
||||
'.env' => 'Konfigurationsdatei (wird automatisch erstellt)',
|
||||
'.env.example' => 'Vorlage fuer .env',
|
||||
'vendor/autoload.php' => 'Composer-Abhaengigkeiten',
|
||||
'bootstrap/app.php' => 'Laravel-Bootstrap',
|
||||
'storage/installed' => 'Installations-Marker (fehlt bei Erstinstallation)',
|
||||
];
|
||||
|
||||
foreach ($files as $file => $desc) {
|
||||
$full = $basePath . '/' . $file;
|
||||
$exists = file_exists($full);
|
||||
// storage/installed SOLL bei Erstinstallation fehlen
|
||||
$isOptional = ($file === 'storage/installed' || $file === '.env');
|
||||
|
||||
$results[] = [
|
||||
'group' => 'Dateien',
|
||||
'name' => $file,
|
||||
'value' => $exists ? 'Vorhanden' : 'Fehlt',
|
||||
'ok' => $exists || $isOptional,
|
||||
'hint' => $desc,
|
||||
];
|
||||
}
|
||||
|
||||
// ─── Webserver ───────────────────────────────────────────────
|
||||
$results[] = [
|
||||
'group' => 'Webserver',
|
||||
'name' => 'Server-Software',
|
||||
'value' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unbekannt',
|
||||
'ok' => true,
|
||||
'hint' => '',
|
||||
];
|
||||
|
||||
$results[] = [
|
||||
'group' => 'Webserver',
|
||||
'name' => 'Document Root',
|
||||
'value' => $_SERVER['DOCUMENT_ROOT'] ?? 'Unbekannt',
|
||||
'ok' => true,
|
||||
'hint' => 'Muss auf den public/-Ordner zeigen.',
|
||||
];
|
||||
|
||||
$results[] = [
|
||||
'group' => 'Webserver',
|
||||
'name' => 'Script-Pfad',
|
||||
'value' => __FILE__,
|
||||
'ok' => true,
|
||||
'hint' => '',
|
||||
];
|
||||
|
||||
$results[] = [
|
||||
'group' => 'Webserver',
|
||||
'name' => 'PHP-User',
|
||||
'value' => function_exists('posix_getpwuid') ? (posix_getpwuid(posix_geteuid())['name'] ?? posix_geteuid()) : get_current_user(),
|
||||
'ok' => true,
|
||||
'hint' => 'Unter diesem User laeuft PHP.',
|
||||
];
|
||||
|
||||
$results[] = [
|
||||
'group' => 'Webserver',
|
||||
'name' => 'mod_rewrite',
|
||||
'value' => (function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules())) ? 'Aktiv' : 'Nicht pruefbar / Nicht aktiv',
|
||||
'ok' => true, // Can't reliably detect
|
||||
'hint' => 'Wird fuer saubere URLs benoetigt.',
|
||||
];
|
||||
|
||||
// ─── index.php Datei-Check ───────────────────────────────────
|
||||
$indexPath = __DIR__ . '/index.php';
|
||||
$indexExists = file_exists($indexPath);
|
||||
$indexSize = $indexExists ? filesize($indexPath) : 0;
|
||||
$indexMtime = $indexExists ? date('Y-m-d H:i:s', filemtime($indexPath)) : '-';
|
||||
$indexFirstLines = $indexExists ? implode("\n", array_slice(file($indexPath), 0, 10)) : '';
|
||||
$hasTryCatch = $indexExists && strpos(file_get_contents($indexPath), 'Throwable') !== false;
|
||||
|
||||
$results[] = [
|
||||
'group' => 'index.php Pruefung',
|
||||
'name' => 'Dateigroesse',
|
||||
'value' => $indexSize . ' Bytes',
|
||||
'ok' => $indexSize > 1000,
|
||||
'hint' => 'Neue index.php sollte ueber 5000 Bytes sein.',
|
||||
];
|
||||
$results[] = [
|
||||
'group' => 'index.php Pruefung',
|
||||
'name' => 'Letzte Aenderung',
|
||||
'value' => $indexMtime,
|
||||
'ok' => true,
|
||||
'hint' => '',
|
||||
];
|
||||
$results[] = [
|
||||
'group' => 'index.php Pruefung',
|
||||
'name' => 'try-catch vorhanden',
|
||||
'value' => $hasTryCatch ? 'Ja' : 'Nein (ALTE VERSION!)',
|
||||
'ok' => $hasTryCatch,
|
||||
'hint' => 'Bitte die aktuelle index.php erneut hochladen.',
|
||||
];
|
||||
|
||||
// ─── Laravel Boot-Test ───────────────────────────────────────
|
||||
$bootSteps = [];
|
||||
$bootError = null;
|
||||
|
||||
// Schritt 1: Autoloader laden
|
||||
try {
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
$bootSteps[] = ['name' => 'vendor/autoload.php laden', 'ok' => true, 'error' => ''];
|
||||
} catch (\Throwable $e) {
|
||||
$bootSteps[] = ['name' => 'vendor/autoload.php laden', 'ok' => false, 'error' => $e->getMessage()];
|
||||
$bootError = $e;
|
||||
}
|
||||
|
||||
// Schritt 2: Bootstrap laden (nur wenn Schritt 1 ok)
|
||||
if (!$bootError) {
|
||||
try {
|
||||
$app = require_once __DIR__ . '/../bootstrap/app.php';
|
||||
$bootSteps[] = ['name' => 'bootstrap/app.php laden', 'ok' => true, 'error' => ''];
|
||||
} catch (\Throwable $e) {
|
||||
$bootSteps[] = ['name' => 'bootstrap/app.php laden', 'ok' => false, 'error' => $e->getMessage()];
|
||||
$bootError = $e;
|
||||
}
|
||||
}
|
||||
|
||||
// Schritt 3: Kernel erstellen (nur wenn Schritt 2 ok)
|
||||
if (!$bootError && isset($app)) {
|
||||
try {
|
||||
$kernel = $app->make(\Illuminate\Contracts\Http\Kernel::class);
|
||||
$bootSteps[] = ['name' => 'HTTP-Kernel erstellen', 'ok' => true, 'error' => ''];
|
||||
} catch (\Throwable $e) {
|
||||
$bootSteps[] = ['name' => 'HTTP-Kernel erstellen', 'ok' => false, 'error' => $e->getMessage()];
|
||||
$bootError = $e;
|
||||
}
|
||||
}
|
||||
|
||||
// Schritt 4: Request-Handling simulieren (nur wenn Schritt 3 ok)
|
||||
if (!$bootError && isset($app)) {
|
||||
try {
|
||||
// Simuliere einen GET / Request
|
||||
$testRequest = \Illuminate\Http\Request::create('/', 'GET');
|
||||
$response = $app->make(\Illuminate\Contracts\Http\Kernel::class)->handle($testRequest);
|
||||
$statusCode = $response->getStatusCode();
|
||||
$isRedirect = $statusCode >= 300 && $statusCode < 400;
|
||||
$redirectTo = $isRedirect ? $response->headers->get('Location', '') : '';
|
||||
|
||||
$bootSteps[] = [
|
||||
'name' => 'Request-Handling (GET /)',
|
||||
'ok' => true,
|
||||
'error' => 'Status ' . $statusCode . ($isRedirect ? ' → Redirect nach ' . $redirectTo : ''),
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
$bootSteps[] = ['name' => 'Request-Handling (GET /)', 'ok' => false, 'error' => $e->getMessage()];
|
||||
$bootError = $e;
|
||||
}
|
||||
}
|
||||
|
||||
// Schritt 5: Auch /install testen (dort laeuft die eigentliche Seite)
|
||||
if (!$bootError && isset($app)) {
|
||||
try {
|
||||
// Log leeren, damit wir nur den Fehler von diesem Request sehen
|
||||
$logFile = __DIR__ . '/../storage/logs/laravel.log';
|
||||
@file_put_contents($logFile, '');
|
||||
|
||||
// Debug aktivieren, damit die Exception geloggt wird
|
||||
config(['app.debug' => true]);
|
||||
|
||||
$installRequest = \Illuminate\Http\Request::create('/install', 'GET');
|
||||
$installResponse = $app->make(\Illuminate\Contracts\Http\Kernel::class)->handle($installRequest);
|
||||
$installStatus = $installResponse->getStatusCode();
|
||||
|
||||
if ($installStatus >= 500) {
|
||||
// Fehler aus dem Log auslesen
|
||||
$logContent = file_exists($logFile) ? file_get_contents($logFile) : '';
|
||||
// Nur die erste Fehlermeldung extrahieren (bis zur ersten Leerzeile)
|
||||
$logLines = explode("\n", $logContent);
|
||||
$errorMsg = '';
|
||||
foreach ($logLines as $line) {
|
||||
if (strlen($errorMsg) > 1500) break;
|
||||
$errorMsg .= $line . "\n";
|
||||
}
|
||||
$errorMsg = trim($errorMsg) ?: '(kein Log-Eintrag gefunden)';
|
||||
|
||||
$bootSteps[] = [
|
||||
'name' => 'Request-Handling (GET /install)',
|
||||
'ok' => false,
|
||||
'error' => 'Status ' . $installStatus . ' — Fehler aus laravel.log: ' . $errorMsg,
|
||||
];
|
||||
} else {
|
||||
$bootSteps[] = [
|
||||
'name' => 'Request-Handling (GET /install)',
|
||||
'ok' => true,
|
||||
'error' => 'Status ' . $installStatus,
|
||||
];
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$bootSteps[] = ['name' => 'Request-Handling (GET /install)', 'ok' => false, 'error' => $e->getMessage()];
|
||||
$bootError = $e;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── OPcache ─────────────────────────────────────────────────
|
||||
$opcacheEnabled = function_exists('opcache_get_status') && opcache_get_status() !== false;
|
||||
$results[] = [
|
||||
'group' => 'OPcache',
|
||||
'name' => 'OPcache aktiv',
|
||||
'value' => $opcacheEnabled ? 'Ja' : 'Nein',
|
||||
'ok' => true,
|
||||
'hint' => '',
|
||||
];
|
||||
|
||||
if ($opcacheEnabled) {
|
||||
$status = opcache_get_status();
|
||||
$results[] = [
|
||||
'group' => 'OPcache',
|
||||
'name' => 'validate_timestamps',
|
||||
'value' => ini_get('opcache.validate_timestamps') ? 'Ja' : 'Nein (gefaehrlich!)',
|
||||
'ok' => (bool) ini_get('opcache.validate_timestamps'),
|
||||
'hint' => 'Ohne validate_timestamps werden Dateiupdates nicht erkannt.',
|
||||
];
|
||||
|
||||
// OPcache fuer index.php invalidieren
|
||||
$indexInvalidated = opcache_invalidate(__DIR__ . '/index.php', true);
|
||||
$results[] = [
|
||||
'group' => 'OPcache',
|
||||
'name' => 'index.php Cache invalidiert',
|
||||
'value' => $indexInvalidated ? 'Ja (erfolgreich)' : 'Nein / nicht noetig',
|
||||
'ok' => true,
|
||||
'hint' => '',
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($bootSteps as $step) {
|
||||
$results[] = [
|
||||
'group' => 'Laravel Boot-Test',
|
||||
'name' => $step['name'],
|
||||
'value' => $step['ok'] ? 'OK' : 'FEHLER: ' . $step['error'],
|
||||
'ok' => $step['ok'],
|
||||
'hint' => $step['error'],
|
||||
];
|
||||
}
|
||||
|
||||
if ($bootError) {
|
||||
$results[] = [
|
||||
'group' => 'Laravel Boot-Test',
|
||||
'name' => 'Stack-Trace',
|
||||
'value' => $bootError->getFile() . ':' . $bootError->getLine(),
|
||||
'ok' => false,
|
||||
'hint' => $bootError->getTraceAsString(),
|
||||
];
|
||||
}
|
||||
|
||||
// ─── Zusammenfassung ─────────────────────────────────────────
|
||||
$allOk = true;
|
||||
foreach ($results as $r) {
|
||||
if (!$r['ok']) {
|
||||
$allOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── HTML-Ausgabe ────────────────────────────────────────────
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Server-Diagnose</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="min-h-screen bg-gray-100 py-8 px-4">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<div class="text-center mb-6">
|
||||
<h1 class="text-xl font-bold text-gray-900">Server-Diagnose</h1>
|
||||
<p class="text-sm text-gray-500 mt-1">
|
||||
Handball WebApp — Systemcheck
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php if ($allOk): ?>
|
||||
<div class="bg-green-50 border border-green-200 rounded-md p-4 mb-6 text-sm text-green-800">
|
||||
Alle Voraussetzungen sind erfuellt. Die Installation sollte funktionieren.
|
||||
<br>Rufe die Hauptseite auf, um den Installer zu starten.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="bg-red-50 border border-red-200 rounded-md p-4 mb-6 text-sm text-red-800">
|
||||
Es gibt Probleme, die behoben werden muessen (rot markiert).
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
$currentGroup = '';
|
||||
foreach ($results as $r):
|
||||
if ($r['group'] !== $currentGroup):
|
||||
if ($currentGroup !== '') echo '</tbody></table></div>';
|
||||
$currentGroup = $r['group'];
|
||||
?>
|
||||
<div class="bg-white rounded-lg shadow-md mb-4 overflow-hidden">
|
||||
<h2 class="bg-gray-50 px-4 py-2 text-sm font-semibold text-gray-700 border-b"><?php echo htmlspecialchars($currentGroup); ?></h2>
|
||||
<table class="w-full text-sm">
|
||||
<tbody>
|
||||
<?php endif; ?>
|
||||
<tr class="border-b border-gray-100 <?php echo $r['ok'] ? '' : 'bg-red-50'; ?>">
|
||||
<td class="px-4 py-2 font-mono text-gray-800 whitespace-nowrap"><?php echo htmlspecialchars($r['name']); ?></td>
|
||||
<td class="px-4 py-2 text-gray-600"><?php echo htmlspecialchars($r['value']); ?></td>
|
||||
<td class="px-2 py-2 text-center w-8">
|
||||
<?php if ($r['ok']): ?>
|
||||
<span class="text-green-500">✓</span>
|
||||
<?php else: ?>
|
||||
<span class="text-red-500 font-bold">✗</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if (!$r['ok'] && $r['hint']): ?>
|
||||
<tr class="bg-red-50 border-b border-red-100">
|
||||
<td colspan="3" class="px-4 py-1 text-xs text-red-600">
|
||||
<pre class="whitespace-pre-wrap break-all">→ <?php echo htmlspecialchars($r['hint']); ?></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody></table>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center gap-4 mt-6">
|
||||
<a href="check.php" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700">
|
||||
Erneut pruefen
|
||||
</a>
|
||||
<?php if ($allOk): ?>
|
||||
<a href="/" class="px-4 py-2 text-sm font-medium text-white bg-green-600 rounded-md hover:bg-green-700">
|
||||
Installation starten
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<p class="text-center text-xs text-gray-400 mt-6">
|
||||
Diese Datei nach erfolgreicher Installation loeschen (check.php).
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user