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, '/'));
}
}