Passed
Pull Request — master (#222)
by Dmitriy
02:35
created

UrlHandler   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 43
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 10
eloc 18
dl 0
loc 43
ccs 19
cts 19
cp 1
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A convertIdn() 0 10 2
A validate() 0 22 6
A idnToAscii() 0 5 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Yiisoft\Validator\Result;
8
use Yiisoft\Validator\ValidationContext;
9
use function is_string;
10
use function strlen;
11
use Yiisoft\Validator\Exception\UnexpectedRuleException;
12
13
/**
14
 * Validates that the value is a valid HTTP or HTTPS URL.
15
 *
16
 * Note that this rule only checks if the URL scheme and host part are correct.
17
 * It does not check the remaining parts of a URL.
18
 */
19
final class UrlHandler implements RuleHandlerInterface
20
{
21 44
    public function validate(mixed $value, object $rule, ?ValidationContext $context = null): Result
22
    {
23 44
        if (!$rule instanceof Url) {
24 1
            throw new UnexpectedRuleException(Url::class, $rule);
25
        }
26
27 43
        $result = new Result();
28
29
        // make sure the length is limited to avoid DOS attacks
30 43
        if (is_string($value) && strlen($value) < 2000) {
31 41
            if ($rule->enableIDN) {
32 9
                $value = $this->convertIdn($value);
33
            }
34
35 41
            if (preg_match($rule->getPattern(), $value)) {
36 24
                return $result;
37
            }
38
        }
39
40 19
        $result->addError($rule->message);
41
42 19
        return $result;
43
    }
44
45 9
    private function idnToAscii(string $idn): string
46
    {
47 9
        $result = idn_to_ascii($idn, 0, INTL_IDNA_VARIANT_UTS46);
48
49 9
        return $result === false ? '' : $result;
50
    }
51
52 9
    private function convertIdn(string $value): string
53
    {
54 9
        if (!str_contains($value, '://')) {
55 5
            return $this->idnToAscii($value);
56
        }
57
58 4
        return preg_replace_callback(
59
            '/:\/\/([^\/]+)/',
60 4
            fn ($matches) => '://' . $this->idnToAscii($matches[1]),
61
            $value
62
        );
63
    }
64
}
65