UrlUtils::resolveRelativeUrl()   B
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 25
ccs 12
cts 12
cp 1
rs 8.439
cc 5
eloc 14
nc 4
nop 2
crap 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GoetasWebservices\XML\XSDReader\Utils;
6
7
class UrlUtils
8
{
9 67
    public static function resolveRelativeUrl(string $base, string $rel): string
10
    {
11 67
        if ('' === trim($rel)) {
12 2
            return $base;
13
        } elseif (
14
        /* return if already absolute URL */
15 66
            parse_url($rel, PHP_URL_SCHEME) !== null ||
16 66
            substr($rel, 0, 2) === '//'
17
        ) {
18 58
            return $rel;
19
        } elseif (
20
        /* queries and anchors */
21 9
            in_array(
22 9
                $rel[0],
23
                [
24 9
                    '#',
25
                    '?',
26
                ],
27 9
                true
28
            )
29
        ) {
30 2
            return $base.$rel;
31
        }
32
33 9
        return static::resolveRelativeUrlAfterEarlyChecks($base, $rel);
34
    }
35
36
    /**
37
     * @param string $base
38
     * @param string $rel
39
     *
40
     * @return string
41
     */
42 9
    protected static function resolveRelativeUrlAfterEarlyChecks(string $base, string $rel): string
43
    {
44
        /* fix url file for Windows */
45 9
        $base = preg_replace('#^file:\/\/([^/])#', 'file:///\1', $base);
46
47
        /**
48
         * @var mixed[]
49
         *
50
         * parse base URL and convert to local variables:
51
         * $scheme, $host, $path
52
         */
53 9
        $parts = parse_url($base);
54
55 9
        return static::resolveRelativeUrlToAbsoluteUrl(
56 9
            $rel,
57
            (
58 9
                $rel[0] === '/'
59 4
                    ? ''  // destroy path if relative url points to root
60
                    : ( // remove non-directory element from path
61 7
                        isset($parts['path'])
62 7
                            ? preg_replace(
63 7
                                '#/[^/]*$#',
64 7
                                '',
65 7
                                (string) $parts['path']
66
                            )
67 9
                            : ''
68
                    )
69
            ),
70 9
            $parts
71
        );
72
    }
73
74 9
    protected static function resolveRelativeUrlToAbsoluteUrl(
75
        string $rel,
76
        string $path,
77
        array $parts
78
    ): string {
79
        /* Build absolute URL */
80 9
        $abs = '';
81
82 9
        if (isset($parts['host'])) {
83 5
            $abs .= (string) $parts['host'];
84
        }
85
86 9
        if (isset($parts['port'])) {
87
            $abs .= ':'.(string) $parts['port'];
88
        }
89
90 9
        $abs .= $path.'/'.$rel;
91 9
        $abs = static::replaceSuperfluousSlashes($abs);
92
93 9
        if (isset($parts['scheme'])) {
94 6
            $abs = (string) $parts['scheme'].'://'.$abs;
95
        }
96
97 9
        return $abs;
98
    }
99
100
    /**
101
     * replace superfluous slashes with a single slash.
102
     * covers:
103
     * //
104
     * /./
105
     * /foo/../.
106
     */
107 9
    protected static function replaceSuperfluousSlashes(string $abs): string
108
    {
109 9
        $n = 1;
110
        do {
111 9
            $abs = preg_replace(
112 9
                '#(?:(?:/\.?/)|(?!\.\.)[^/]+/\.\./)#',
113 9
                '/',
114 9
                $abs,
115 9
                -1,
116 9
                $n
117
            );
118 9
        } while ($n > 0);
119
120 9
        return $abs;
121
    }
122
}
123