UrlUtils::resolveRelativeUrlAfterEarlyChecks()   A
last analyzed

Complexity

Conditions 3
Paths 1

Size

Total Lines 29
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

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