Furious-PHP/psr7

View on GitHub
src/Filter/UriFilter.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

declare(strict_types=1);

namespace Furious\Psr7\Filter;

use Furious\Psr7\Exception\InvalidArgumentException;
use Furious\Psr7\Exception\InvalidPortException;
use function is_string;
use function preg_replace_callback;
use function rawurlencode;

final class UriFilter
{
    private const SCENARIOS = [
        'http' => 80,
        'https' => 443
    ];
    private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~';
    private const CHAR_SUB_DELIMITERS = '!\$&\'\(\)\*\+,;=';

    public function filterPort(string $scheme, ?int $port): ?int
    {
        if (null === $port) {
            return null;
        }

        $port = (int) $port;
        if (0 > $port or 0xffff < $port) {
            throw new InvalidPortException(sprintf('Invalid port: %d. Must be between 0 and 65535', $port));
        }

        return $this->isNonStandardPort($scheme, $port) ? $port : null;
    }

    public function filterPath($path): string
    {
        if (!is_string($path)) {
            throw new InvalidArgumentException('Path must be a string');
        }

        return preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMITERS . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/', [__CLASS__, 'rawUrlEncodeMatchZero'], $path);
    }

    public function filterQuery($string): string
    {
        if (!is_string($string)) {
            throw new InvalidPortException('Query must be a string');
        }

        return preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMITERS . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/', [__CLASS__, 'rawUrlEncodeMatchZero'], $string);
    }

    public function filterFragment($string): string
    {
        if (!is_string($string)) {
            throw new InvalidPortException('Fragment must be a string');
        }

        return preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMITERS . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/', [__CLASS__, 'rawUrlEncodeMatchZero'], $string);
    }

    private function isNonStandardPort(string $scheme, int $port): bool
    {
        return
            !isset(self::SCENARIOS[$scheme]) or
            self::SCENARIOS[$scheme] !== $port;
    }

    private function rawUrlEncodeMatchZero(array $match): string
    {
        return rawurlencode($match[0]);
    }
}