sync: Zahlungsstrecke, PG-Events, Fatal-Log und PayPal-v2-Blaupause vom Live-Stand 2026-09-13
Deploy to Dev / deploy (push) Successful in 1s

This commit is contained in:
Thomas Bartelt
2026-09-13 19:20:24 +02:00
parent 20d55f77b8
commit af81e8f63a
22 changed files with 1963 additions and 58 deletions
+53
View File
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace PaypalV2;
/**
* Verifiziert PayPal-Webhook-Signaturen serverseitig gegen die PayPal-API.
* Nur so ist ein eingehendes Event vertrauenswuerdig.
*/
final class Webhook
{
/**
* @param array<string,string> $headers Request-Header (Schluessel lowercase)
* @param string $rawBody Roher Request-Body (unveraendert!)
*/
public function verify(array $headers, string $rawBody): bool
{
$webhookId = Config::webhookId();
if ($webhookId === '') {
\error_log('PayPal v2 Webhook: keine webhook_id konfiguriert – Event abgelehnt.');
return false;
}
$event = \json_decode($rawBody, true);
if (!\is_array($event)) {
return false;
}
$payload = [
'transmission_id' => $headers['paypal-transmission-id'] ?? '',
'transmission_time' => $headers['paypal-transmission-time'] ?? '',
'cert_url' => $headers['paypal-cert-url'] ?? '',
'auth_algo' => $headers['paypal-auth-algo'] ?? '',
'transmission_sig' => $headers['paypal-transmission-sig'] ?? '',
'webhook_id' => $webhookId,
'webhook_event' => $event,
];
foreach (['transmission_id', 'transmission_time', 'cert_url', 'auth_algo', 'transmission_sig'] as $k) {
if ($payload[$k] === '') {
return false;
}
}
[$status, $body] = (new PayPalClient())->request(
'POST',
'/v1/notifications/verify-webhook-signature',
$payload
);
return $status === 200 && (($body['verification_status'] ?? '') === 'SUCCESS');
}
}