Vor dem ersten Abruf soll klar sein, ob der Host das Postfach ueberhaupt erreicht - und auf welchem Weg. Das Skript meldet PHP-Version, ob die imap-Erweiterung geladen ist, ob die PAYPAL_*-Einstellungen gesetzt sind, und oeffnet das Postfach testweise ueber eine reine TLS-Verbindung. Damit ist auch ohne die Erweiterung belegbar, dass ein Abruf moeglich waere - seit PHP 8.4 ist imap kein Bestandteil von PHP mehr und laesst sich auf einem Webhosting nicht einfach nachruesten. Bewusst nur lesend: EXAMINE statt SELECT, kein Flag wird gesetzt. Das Passwort wird nie ausgegeben, nur seine Laenge als Tippfehler-Probe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
177 lines
6.6 KiB
PHP
177 lines
6.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Diagnose fuer den PayPal-Mailabruf: klaert in einem Lauf, ob dieser Host
|
|
* das Postfach ueberhaupt erreichen kann - und auf welchem Weg.
|
|
*
|
|
* Geprueft wird:
|
|
* 1. PHP-Version und ob die imap-Erweiterung geladen ist (seit PHP 8.4 ist
|
|
* sie nicht mehr Teil von PHP, sondern nur noch ueber PECL zu haben).
|
|
* 2. Ob die PAYPAL_*-Einstellungen in der env.local.php gesetzt sind.
|
|
* 3. Ob sich das Postfach ohne die Erweiterung erreichen laesst - ueber
|
|
* eine reine TLS-Verbindung, wie sie auch ein Fallback nutzen wuerde.
|
|
*
|
|
* Der Test ist bewusst nur lesend: EXAMINE statt SELECT, kein Flag wird
|
|
* gesetzt, keine Mail veraendert. Das Passwort wird nie ausgegeben.
|
|
*
|
|
* Aufruf (Plesk: Geplante Aufgabe vom Typ "PHP-Skript"):
|
|
* /httpdocs/scripts/check-imap-support.php
|
|
*/
|
|
|
|
if (PHP_SAPI !== 'cli') {
|
|
http_response_code(403);
|
|
exit("Dieses Skript ist nur fuer die Kommandozeile gedacht.\n");
|
|
}
|
|
|
|
require_once __DIR__ . '/../app/bootstrap.php';
|
|
|
|
function imap_check_line(string $label, string $value): void
|
|
{
|
|
printf("%-28s %s\n", $label . ':', $value);
|
|
}
|
|
|
|
echo "=== PHP ===\n";
|
|
imap_check_line('Version', PHP_VERSION);
|
|
imap_check_line('imap-Erweiterung', function_exists('imap_open') ? 'geladen' : 'FEHLT');
|
|
imap_check_line('openssl', extension_loaded('openssl') ? 'vorhanden' : 'FEHLT');
|
|
imap_check_line('Sockets/Streams', function_exists('stream_socket_client') ? 'vorhanden' : 'FEHLT');
|
|
if (!function_exists('imap_open') && version_compare(PHP_VERSION, '8.4', '>=')) {
|
|
echo "Hinweis: Ab PHP 8.4 ist imap kein Bestandteil von PHP mehr. Entweder den\n"
|
|
. "PHP-Handler dieses Vhosts auf 8.3 stellen oder den Abruf ueber eine reine\n"
|
|
. "TLS-Verbindung laufen lassen (siehe Test unten).\n";
|
|
}
|
|
|
|
echo "\n=== Einstellungen (env.local.php) ===\n";
|
|
$host = app_env('PAYPAL_IMAP_HOST');
|
|
$user = app_env('PAYPAL_IMAP_USER');
|
|
$pass = app_env('PAYPAL_IMAP_PASS');
|
|
$port = (int) app_env('PAYPAL_IMAP_PORT', '993');
|
|
$flags = (string) app_env('PAYPAL_IMAP_FLAGS', '/imap/ssl');
|
|
$mailbox = (string) app_env('PAYPAL_IMAP_MAILBOX', 'INBOX');
|
|
|
|
imap_check_line('PAYPAL_INBOX_BASE', (string) (app_env('PAYPAL_INBOX_BASE') ?? '(nicht gesetzt)'));
|
|
imap_check_line('PAYPAL_IMAP_HOST', (string) ($host ?? '(nicht gesetzt)'));
|
|
imap_check_line('PAYPAL_IMAP_PORT', (string) $port);
|
|
imap_check_line('PAYPAL_IMAP_FLAGS', $flags);
|
|
imap_check_line('PAYPAL_IMAP_USER', (string) ($user ?? '(nicht gesetzt)'));
|
|
// Das Passwort selbst gehoert nicht in ein Protokoll, das per Mail
|
|
// verschickt oder weitergereicht wird - nur die Laenge als Tippfehler-Probe.
|
|
imap_check_line('PAYPAL_IMAP_PASS', $pass === null ? '(nicht gesetzt)' : 'gesetzt (' . strlen($pass) . ' Zeichen)');
|
|
imap_check_line('PAYPAL_IMAP_MAILBOX', $mailbox);
|
|
|
|
if ($host === null || $user === null || $pass === null) {
|
|
echo "\nOhne Host, Benutzer und Passwort ist kein Verbindungstest moeglich.\n";
|
|
exit(1);
|
|
}
|
|
|
|
/**
|
|
* Liest die Antwort bis zur Zeile mit dem gesuchten Tag.
|
|
*
|
|
* @return array{ok: bool, lines: list<string>}
|
|
*/
|
|
function imap_check_read($sock, string $tag): array
|
|
{
|
|
$lines = [];
|
|
while (($line = fgets($sock)) !== false) {
|
|
$line = rtrim($line, "\r\n");
|
|
$lines[] = $line;
|
|
if (str_starts_with($line, $tag . ' ')) {
|
|
return ['ok' => str_starts_with($line, $tag . ' OK'), 'lines' => $lines];
|
|
}
|
|
}
|
|
|
|
return ['ok' => false, 'lines' => $lines];
|
|
}
|
|
|
|
function imap_check_send($sock, string $tag, string $command): array
|
|
{
|
|
fwrite($sock, $tag . ' ' . $command . "\r\n");
|
|
|
|
return imap_check_read($sock, $tag);
|
|
}
|
|
|
|
echo "\n=== Verbindungstest ohne imap-Erweiterung (nur lesend) ===\n";
|
|
|
|
// Port 993 = TLS von Anfang an; alles andere (typisch 143) = STARTTLS.
|
|
$implizitesTls = $port === 993 || str_contains($flags, '/ssl');
|
|
$adresse = ($implizitesTls ? 'ssl://' : 'tcp://') . $host . ':' . $port;
|
|
imap_check_line('Verbindung', $adresse . ($implizitesTls ? ' (TLS sofort)' : ' (STARTTLS)'));
|
|
|
|
$fehlerNr = 0;
|
|
$fehlerText = '';
|
|
$sock = @stream_socket_client($adresse, $fehlerNr, $fehlerText, 15);
|
|
if ($sock === false) {
|
|
echo "FEHLER: Verbindung nicht moeglich ({$fehlerNr}: {$fehlerText})\n";
|
|
echo "Moegliche Ursachen: Host/Port falsch, ausgehende Verbindungen gesperrt,\n"
|
|
. "oder TLS-Zertifikat nicht akzeptiert.\n";
|
|
exit(1);
|
|
}
|
|
stream_set_timeout($sock, 15);
|
|
|
|
$greeting = rtrim((string) fgets($sock), "\r\n");
|
|
imap_check_line('Begruessung', $greeting !== '' ? $greeting : '(keine)');
|
|
|
|
if (!$implizitesTls) {
|
|
$start = imap_check_send($sock, 'a0', 'STARTTLS');
|
|
if (!$start['ok'] || !@stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
|
|
echo "FEHLER: STARTTLS fehlgeschlagen - ohne Verschluesselung wird nicht angemeldet.\n";
|
|
exit(1);
|
|
}
|
|
imap_check_line('STARTTLS', 'ok');
|
|
}
|
|
|
|
// Anfuehrungszeichen und Backslashes im Passwort maskieren (IMAP-Quoting).
|
|
$quote = static fn(string $wert): string => '"' . str_replace(['\\', '"'], ['\\\\', '\\"'], $wert) . '"';
|
|
|
|
$login = imap_check_send($sock, 'a1', 'LOGIN ' . $quote($user) . ' ' . $quote($pass));
|
|
if (!$login['ok']) {
|
|
echo "FEHLER: Anmeldung abgelehnt.\n";
|
|
echo ' Antwort: ' . end($login['lines']) . "\n";
|
|
fwrite($sock, "a9 LOGOUT\r\n");
|
|
fclose($sock);
|
|
exit(1);
|
|
}
|
|
imap_check_line('Anmeldung', 'ok');
|
|
|
|
// EXAMINE statt SELECT: oeffnet das Postfach ausdruecklich nur lesend.
|
|
$examine = imap_check_send($sock, 'a2', 'EXAMINE ' . $quote($mailbox));
|
|
if (!$examine['ok']) {
|
|
echo "FEHLER: Postfach '{$mailbox}' nicht zu oeffnen.\n";
|
|
echo ' Antwort: ' . end($examine['lines']) . "\n";
|
|
fwrite($sock, "a9 LOGOUT\r\n");
|
|
fclose($sock);
|
|
exit(1);
|
|
}
|
|
$gesamt = 0;
|
|
foreach ($examine['lines'] as $line) {
|
|
if (preg_match('/^\* (\d+) EXISTS/', $line, $m)) {
|
|
$gesamt = (int) $m[1];
|
|
}
|
|
}
|
|
imap_check_line('Postfach', $mailbox . ' geoeffnet');
|
|
imap_check_line('Mails gesamt', (string) $gesamt);
|
|
|
|
$search = imap_check_send($sock, 'a3', 'SEARCH UNSEEN');
|
|
$ungelesen = 0;
|
|
foreach ($search['lines'] as $line) {
|
|
if (str_starts_with($line, '* SEARCH')) {
|
|
$ids = trim(substr($line, strlen('* SEARCH')));
|
|
$ungelesen = $ids === '' ? 0 : count(preg_split('/\s+/', $ids) ?: []);
|
|
}
|
|
}
|
|
imap_check_line('davon ungelesen', (string) $ungelesen);
|
|
|
|
fwrite($sock, "a9 LOGOUT\r\n");
|
|
fclose($sock);
|
|
|
|
echo "\nErgebnis: Postfach erreichbar und Zugangsdaten gueltig.\n";
|
|
if (function_exists('imap_open')) {
|
|
echo "Die imap-Erweiterung ist vorhanden - scripts/fetch-paypal-payments.php\n"
|
|
. "laeuft ohne weitere Aenderung. Naechster Schritt: derselbe Task mit --dry-run.\n";
|
|
} else {
|
|
echo "Die imap-Erweiterung fehlt, das Postfach ist aber ueber die reine\n"
|
|
. "TLS-Verbindung erreichbar - ein Abruf ohne Erweiterung ist also moeglich.\n";
|
|
}
|