UrlFixer   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 44
c 1
b 0
f 0
dl 0
loc 113
rs 10
wmc 18

3 Methods

Rating   Name   Duplication   Size   Complexity  
B fixCss() 0 33 9
A __construct() 0 3 1
B fixUrl() 0 40 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Framework\Assets;
6
7
class UrlFixer
8
{
9
    protected const QUOTES = ['"', "'"];
10
11
    protected string $cacheUrl = '';
12
13
    /**
14
     * UrlFixer constructor.
15
     *
16
     * @param string $cacheUrl
17
     */
18
    public function __construct(string $cacheUrl)
19
    {
20
        $this->cacheUrl = $cacheUrl;
21
    }
22
23
    /**
24
     * FixCSS tries to compensate for minification of CSS stylesheets
25
     * - It looks for URLs
26
     * - Maintains optional quotes used
27
     * - Calls fixUrl to modify the URL if needed
28
     *
29
     * @param string $content
30
     * @param string $path
31
     *
32
     * @return string
33
     */
34
    public function fixCss(string $content, string $path): string
35
    {
36
        if (!preg_match_all('/url\s*\(\s*(\S*)\s*\)/Umsi', $content, $matches)) {
37
            return $content;
38
        }
39
40
        foreach ($matches[1] as $i => $match) {
41
            if (mb_strlen($match) < 2) {
42
                continue;
43
            }
44
45
            $q = mb_substr($match, 0, 1);
46
            $q = in_array($q, static::QUOTES, true) ? $q : '';
47
48
            if ($q && mb_substr($match, -1) !== $q) {
49
                continue;
50
            }
51
52
            $url = $q ? mb_substr($match, 1, -1) : $match;
53
54
            $fixedUrl = $this->fixUrl($url, $path);
55
56
            if ($fixedUrl == $url) {
57
                continue;
58
            }
59
60
            $search  = $matches[0][$i];
61
            $replace = 'url(' . $q . $fixedUrl . $q . ')';
62
63
            $content = str_replace($search, $replace, $content);
64
        }
65
66
        return $content;
67
    }
68
69
    /**
70
     * Fix URL will try to turn a URL into a full qualified URI
71
     *
72
     * - Data URLs skipped
73
     * - Already fully qualified URIs skipped
74
     *
75
     * @param string $url
76
     * @param string $path
77
     *
78
     * @return string
79
     */
80
    protected function fixUrl(string $url, string $path): string
81
    {
82
        if (mb_substr($url, 0, 5) === 'data:') {
83
            return $url;
84
        }
85
86
        if (strpos($url, '://') !== false) {
87
            return $url;
88
        }
89
90
        $ch = mb_substr($url, 0, 1);
91
        if ($ch === '/') {
92
            return $this->cacheUrl . $url;
93
        }
94
95
        while (mb_substr($url, 0, 2) == './') {
96
            $url = mb_substr($url, 2);
97
        }
98
99
        $out = 0;
100
        while (mb_substr($url, 0, 3) == '../') {
101
            $out++;
102
            $url = mb_substr($url, 3);
103
        }
104
105
        $pathDir = dirname($path);
106
107
        $urlParts  = explode(DIRECTORY_SEPARATOR, $url);
108
        $pathParts = $pathDir === '.' ? [] : explode(DIRECTORY_SEPARATOR, $pathDir);
109
        if (count($pathParts) < $out) {
110
            return $this->cacheUrl . DIRECTORY_SEPARATOR . $urlParts[count($urlParts) - 1];
111
        }
112
113
        $urlParts  = array_slice($urlParts, $out);
114
        $pathParts = array_slice($pathParts, $out - 1);
115
116
        $path = implode(DIRECTORY_SEPARATOR, $pathParts);
117
        $url  = implode(DIRECTORY_SEPARATOR, $urlParts);
118
119
        return $this->cacheUrl . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . $url;
120
    }
121
}
122