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

UrlHandler::convertIdn()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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