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

UrlHandler::validate()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

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