fix: harden url mapping validation

This commit is contained in:
Keith Solomon
2026-04-26 14:34:44 -05:00
parent 8d7abc8536
commit 4880613b67
4 changed files with 95 additions and 6 deletions
+53 -1
View File
@@ -14,6 +14,10 @@ final class UrlMapping {
throw new \InvalidArgumentException( 'Source and destination URLs are required.' );
}
if ( ! $this->isAbsoluteUrl( $source_url ) || ! $this->isAbsoluteUrl( $destination_url ) ) {
throw new \InvalidArgumentException( 'Source and destination URLs must include a scheme and host.' );
}
$this->source_url = $source_url;
$this->destination_url = $destination_url;
}
@@ -27,6 +31,54 @@ final class UrlMapping {
}
private function normalizeUrl( string $url ): string {
return rtrim( trim( $url ), '/' );
$url = trim( $url );
$parts = wp_parse_url( $url );
if ( ! is_array( $parts ) || ! isset( $parts['path'] ) || '/' !== $parts['path'] ) {
return $url;
}
unset( $parts['path'] );
return $this->buildUrl( $parts );
}
private function isAbsoluteUrl( string $url ): bool {
$parts = wp_parse_url( $url );
return is_array( $parts ) && ! empty( $parts['scheme'] ) && ! empty( $parts['host'] );
}
/**
* @param array<string, mixed> $parts URL parts.
*/
private function buildUrl( array $parts ): string {
$url = (string) $parts['scheme'] . '://';
if ( isset( $parts['user'] ) ) {
$url .= (string) $parts['user'];
if ( isset( $parts['pass'] ) ) {
$url .= ':' . (string) $parts['pass'];
}
$url .= '@';
}
$url .= (string) $parts['host'];
if ( isset( $parts['port'] ) ) {
$url .= ':' . (string) $parts['port'];
}
if ( isset( $parts['query'] ) ) {
$url .= '?' . (string) $parts['query'];
}
if ( isset( $parts['fragment'] ) ) {
$url .= '#' . (string) $parts['fragment'];
}
return $url;
}
}