← Code-Übersicht

WetellUrlPolicy.php

Pfad: src/Infrastructure/Rechnung/WetellUrlPolicy.php

Ext: php

Größe: 1904 Bytes

Geändert: 2026-07-16 17:10:12+02

<?php
declare(strict_types=1);

namespace Demo\Infrastructure\Rechnung;

use RuntimeException;

/**
 * Erlaubt ausschliesslich HTTPS-Ziele auf dem konfigurierten WEtell-Host.
 */
final class WetellUrlPolicy
{
    private readonly string $host;

    /** Leitet den erlaubten Host aus der Rechnungsseite ab. */
    public function __construct(string $invoicesUrl)
    {
        $host = parse_url($invoicesUrl, PHP_URL_HOST);
        if (!is_string($host) || $host === '') {
            throw new RuntimeException('WEtell-Host fehlt');
        }
        $this->host = strtolower($host);
        $this->assert($invoicesUrl);
    }

    /** Prueft Schema, Host, Benutzerinfo und Port. */
    public function assert(string $url): string
    {
        $parts = parse_url($url);
        if (!is_array($parts)
            || strtolower((string) ($parts['scheme'] ?? '')) !== 'https'
            || strtolower((string) ($parts['host'] ?? '')) !== $this->host
            || isset($parts['user'], $parts['pass'])
            || (isset($parts['port']) && (int) $parts['port'] !== 443)
        ) {
            throw new RuntimeException('Nicht erlaubtes WEtell-Ziel');
        }
        return $url;
    }

    /** Loest einen relativen Link gegen eine erlaubte Basis auf. */
    public function resolve(string $url, string $base): string
    {
        if (preg_match('~^https://~i', $url) === 1) {
            return $this->assert($url);
        }
        $baseParts = parse_url($this->assert($base));
        $origin = 'https://' . $this->host;
        if (str_starts_with($url, '/')) {
            return $this->assert($origin . $url);
        }
        $path = is_array($baseParts) ? (string) ($baseParts['path'] ?? '/') : '/';
        $directory = rtrim(str_replace('\\', '/', dirname($path)), '/');
        return $this->assert($origin . ($directory === '' ? '' : $directory) . '/' . ltrim($url, '/'));
    }
}