Completed
Push — master ( 7fe6b0...d8a5ea )
by Paweł
02:19
created

Url   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 45
c 3
b 1
f 0
dl 0
loc 88
ccs 44
cts 44
cp 1
rs 10
wmc 20

2 Methods

Rating   Name   Duplication   Size   Complexity  
F normalizeUrl() 0 62 17
A checkDomain() 0 9 3
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Wszetko Sitemap.
7
 *
8
 * (c) Paweł Kłopotek-Główczewski <[email protected]>
9
 *
10
 * This source file is subject to the MIT license that is bundled
11
 * with this source code in the file LICENSE.
12
 */
13
14
namespace Wszetko\Sitemap\Helpers;
15
16
/**
17
 * Class Url.
18
 *
19
 * @package Wszetko\Sitemap\Helpers
20
 */
21
class Url
22
{
23
    /**
24
     * @param string $url
25
     *
26
     * @return bool|string
27
     *
28
     * @see https://bugs.php.net/bug.php?id=52923
29
     * @see https://www.php.net/manual/en/function.parse-url.php#114817
30
     */
31 138
    public static function normalizeUrl(string $url)
32
    {
33 138
        $encodedUrl = preg_replace_callback(
34 138
            '%[^:/@?&=#]+%usD',
35
            function ($matches) {
36 138
                return rawurlencode($matches[0]);
37 138
            },
38 69
            $url
39
        );
40
41 138
        $url = parse_url($encodedUrl);
42
43 138
        if (empty($url) || !isset($url['host'])) {
44 6
            return false;
45
        }
46
47 136
        $url = array_map('urldecode', $url);
48 136
        $url['host'] = idn_to_ascii($url['host'], IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
49
50 136
        if (empty($url['scheme']) || !is_string($url['host']) || !self::checkDomain($url['host'])) {
51 2
            return false;
52
        }
53
54 134
        if (!empty($url['path'])) {
55 16
            $url['path'] = explode('/', $url['path']);
56 16
            $parts = [];
57
58 16
            foreach ($url['path'] as $element) {
59 16
                switch ($element) {
60 16
                    case '.':
61 2
                        break;
62 16
                    case '..':
63 2
                        array_pop($parts);
64
65 2
                        break;
66
                    default:
67 16
                        $parts[] = rawurlencode($element);
68
69 16
                        break;
70
                }
71
            }
72
73 16
            $url['path'] = implode('/', $parts);
74
        }
75
76 134
        if (!empty($url['query'])) {
77 2
            parse_str($url['query'], $query);
78
            array_walk($query, function (&$val, &$var) {
79 2
                $var = rawurlencode($var);
80 2
                $val = rawurlencode($val);
81 2
            });
82 2
            $url['query'] = http_build_query($query);
83
        }
84
85
        return
86 134
            $url['scheme'] . '://'
87 134
            . (isset($url['user']) ? $url['user'] . ((isset($url['pass'])) ? ':' . $url['pass'] : '') . '@' : '')
88 134
            . mb_strtolower($url['host'])
89 134
            . ((isset($url['port'])) ? ':' . $url['port'] : '')
90 134
            . ((isset($url['path'])) ? $url['path'] : '')
91 134
            . ((isset($url['query'])) ? '?' . $url['query'] : '')
92 134
            . ((isset($url['fragment'])) ? '#' . $url['fragment'] : '');
93
    }
94
95
    /**
96
     * @param string $domain
97
     *
98
     * @return bool
99
     */
100 140
    public static function checkDomain(string $domain): bool
101
    {
102 140
        if ('.' == mb_substr($domain, -1) || '.' == mb_substr($domain, 0, 1)) {
103 4
            return false;
104
        }
105
106 140
        $domain = idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
107
108 140
        return (bool) filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
109
    }
110
}
111