Passed
Push — master ( 71e747...f0080c )
by Pouya
01:29
created

isPathStartWithTwoPointSlash()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
4
namespace seosazi\PathConverter;
5
6
7
/**
8
 * Convert paths relative with base tag and domain to absolute path
9
 *
10
 * E.g.
11
 *      href="style.css"
12
 *      and base tag "https://www.seosazi.com/assets/"
13
 *      and web page address "https://www.seosazi.com"
14
 * becomes
15
 *     https://www.seosazi.com/assets/style.css
16
 *
17
 * Or
18
 *E.g.
19
 *      href="../../style.css"
20
 *      and base tag "https://www.seosazi.com/assets/files/"
21
 *      and web page address "https://www.seosazi.com"
22
 * becomes
23
 *     https://www.seosazi.com/style.css
24
 *
25
 *
26
 * Please report bugs on https://github.com/seosazi/path-converter/issues
27
 *
28
 * @author Pouya Pormohamad <[email protected]>
29
 * @copyright Copyright (c) 2020, Pouya Pormohamad. All rights reserved
30
 * @license MIT License
31
 */
32
class ConvertToAbsolutePath implements ConverterInterface
33
{
34
35
    /** @var string */
36
    private $pagePath;
37
    /** @var string|null */
38
    private $baseTag = null;
39
    /** @var string|null  */
40
    private $starterPath=null;
41
    /**
42
     * @var array|false|int|string|null
43
     */
44
    private $baseTagParsing;
45
    /**
46
     * @var array|false|int|string|null
47
     */
48
    private $pagePathParsing;
49
    /**
50
     * @var string
51
     */
52
    private $domain;
53
    private $scheme;
54
55
    /**
56
     * ConvertToAbsolutePath constructor.
57
     * @param $pagePath
58
     */
59
    public function __construct($pagePath=NULL)
60
    {
61
        if(isset($pagePath)) {
62
            $this->setPagePath($pagePath);
63
        }
64
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69
    public function convert($path)
70
    {
71
        // Skip converting if the relative url like http://... or android-app://... etc.
72
        if ($this->isPathAbsoluteOrForAnotherApp($path)) {
73
            return $this->checkPathIsAbsoluteOrForAnotherApp($path);
74
        }
75
        // Treat path as invalid if it is like javascript:... etc.
76
        if ($this->isPathJavaScript($path)) {
77
            return '';
78
        }
79
        // Convert //www.google.com to http://www.google.com
80
        if($this->isPathWithoutScheme($path)) {
81
            return 'http:' . $path;
82
        }
83
        // If the path is a fragment or query string,
84
        // it will be appended to the base url
85
        if($this->isHaveQueryOrFragment($path)) {
86
            return $this->getStarterPath() . $path;
87
        }
88
        // Treat paths with doc root, i.e, /about
89
        if($this->isPathStartWithSlash($path)) {
90
            return $this->onlySitePath($this->getStarterPath()) . $path;
91
        }
92
        // For paths like ./foo, it will be appended to the furthest directory
93
        if($this->isPathStartWithPointSlash($path)) {
94
            return $this->uptoLastDir($this->getStarterPath()) . substr($path, 2);
95
        }
96
        // Convert paths like ../foo or ../../bar
97
        if($this->isPathStartWithTwoPointSlash($path)) {
98
           $removeTwoPointSlash = new RemovePathWithPointPointSlash($this, $path);
99
           return $removeTwoPointSlash->compute();
100
        }
101
        if (empty($path)) {
102
            return $this->getPagePath();
103
        }
104
        // else
105
        return $this->uptoLastDir($this->getStarterPath()) . $path;
106
    }
107
108
    public function onlySitePath($url) {
109
//        $url = preg_replace('/(^https?:\/\/.+?\/)(.*)$/i', '$1', $url);
110
//        return rtrim($url, '/');
111
        $parseUrl = parse_url($url);
112
        if ($this->isCorrectUrl($parseUrl)) {
113
            return '';
114
        }elseif(isset($parseUrl['scheme'])){
115
            return $parseUrl['scheme'] . '://' . $parseUrl['host'];
116
        } else {
117
            return $parseUrl['host'];
118
        }
119
    }
120
121
    // Get the path with last directory
122
    // http://example.com/some/fake/path/page.html => http://example.com/some/fake/path/
123
    public function upToLastDir($url) {
124
        $parseUrl = parse_url($url);
125
        $path = '';
126
        if(isset($parseUrl['path']))
127
            $path = preg_replace('/\/([^\/]+)$/i', '', $parseUrl['path']);
128
        return rtrim($parseUrl['scheme'] . '://' . $parseUrl['host'] . $path, '/') . '/';
129
    }
130
131
132
    public function getPagePath()
133
    {
134
        return $this->pagePath;
135
    }
136
137
    /**
138
     * @param string $pagePath
139
     */
140
    public function setPagePath(string $pagePath): void
141
    {
142
        $this->pagePath = $pagePath;
143
    }
144
145
146
    public function getBaseTag()
147
    {
148
        return $this->baseTag;
149
    }
150
151
    /**
152
     * @param string $baseTag
153
     */
154
    public function setBaseTag(string $baseTag): void
155
    {
156
        $this->baseTag = $baseTag;
157
    }
158
159
    /**
160
     * @return string
161
     */
162
    public function getStarterPath(): string
163
    {
164
        if($this->starterPath===null){
165
            if($this->getBaseTag() === null) {
166
                $this->starterPath =$this->getPagePath();
167
            }elseif(array_key_exists('scheme', $this->getBaseTagParsing())){
0 ignored issues
show
Bug introduced by
It seems like $this->getBaseTagParsing() can also be of type integer and string and true; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
            }elseif(array_key_exists('scheme', /** @scrutinizer ignore-type */ $this->getBaseTagParsing())){
Loading history...
168
                $this->starterPath = $this->getBaseTag() ;
169
            }else{
170
                $this->starterPath = $this->getPagePathParsing()['scheme'] . '://' . $this->getPagePathParsing()['host'] . $this->getBaseTag();
171
            }
172
        }
173
        return $this->starterPath;
174
    }
175
176
    public function getDomain()
177
    {
178
        if ($this->domain === null) {
179
            if($this->getBaseTag() === null) {
180
                $this->domain = $this->getPagePathParsing()['host'] . '/';
181
            }elseif(array_key_exists('scheme', $this->getBaseTagParsing())){
0 ignored issues
show
Bug introduced by
It seems like $this->getBaseTagParsing() can also be of type integer and string and true; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

181
            }elseif(array_key_exists('scheme', /** @scrutinizer ignore-type */ $this->getBaseTagParsing())){
Loading history...
182
                $this->domain = $this->getBaseTagParsing()['host'] . '/';
183
            }else{
184
                $this->domain = $this->getPagePathParsing()['host'] . '/';
185
            }
186
        }
187
        return $this->domain;
188
    }
189
190
    public function getScheme()
191
    {
192
        if ($this->scheme === null) {
193
            if($this->getBaseTag() === null) {
194
                $this->scheme = $this->getPagePathParsing()['scheme'];
195
            }elseif(array_key_exists('scheme', $this->getBaseTagParsing())){
0 ignored issues
show
Bug introduced by
It seems like $this->getBaseTagParsing() can also be of type integer and string and true; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

195
            }elseif(array_key_exists('scheme', /** @scrutinizer ignore-type */ $this->getBaseTagParsing())){
Loading history...
196
                $this->scheme = $this->getBaseTagParsing()['scheme'];
197
            }else{
198
                $this->scheme = $this->getPagePathParsing()['scheme'];
199
            }
200
        }
201
        return $this->scheme;
202
    }
203
204
    public function getBaseTagParsing()
205
    {
206
        if($this->baseTagParsing == null)
207
            $this->baseTagParsing = parse_url($this->getBaseTag());
208
        return $this->baseTagParsing;
209
    }
210
211
    public function getPagePathParsing()
212
    {
213
        if($this->pagePathParsing == null)
214
            $this->pagePathParsing = parse_url($this->getPagePath());
215
        return $this->pagePathParsing;
216
    }
217
218
    /**
219
     * @param $path
220
     * @return bool
221
     */
222
    public function isHaveQueryOrFragment($path): bool
223
    {
224
        return substr($path, 0, 1) == '#' || substr($path, 0, 1) == '?';
225
    }
226
227
    /**
228
     * @param $parseUrl
229
     * @return bool
230
     */
231
    public function isCorrectUrl($parseUrl): bool
232
    {
233
        return !isset($parseUrl['scheme']) AND !isset($parseUrl['host']);
234
    }
235
236
    /**
237
     * @param $path
238
     * @return string
239
     */
240
    public function checkPathIsAbsoluteOrForAnotherApp($path): string
241
    {
242
        if (preg_match('/services:\/\//i', $path))
243
            return '';
244
        if (preg_match('/whatsapp:\/\//i', $path))
245
            return '';
246
        if (preg_match('/tel:/i', $path))
247
            return '';
248
        return $path;
249
    }
250
251
    /**
252
     * @param $path
253
     * @return false|int
254
     */
255
    public function isPathAbsoluteOrForAnotherApp($path)
256
    {
257
        return preg_match('/[a-z0-9-]{1,}(:\/\/)/i', $path);
258
    }
259
260
    /**
261
     * @param $path
262
     * @return false|int
263
     */
264
    public function isPathJavaScript($path)
265
    {
266
        return preg_match('/^[a-zA-Z]{0,}:[^\/]{0,1}/i', $path);
267
    }
268
269
    /**
270
     * @param $path
271
     * @return bool
272
     */
273
    public function isPathWithoutScheme($path): bool
274
    {
275
        return substr($path, 0, 2) == '//';
276
    }
277
278
    /**
279
     * @param $path
280
     * @return bool
281
     */
282
    public function isPathStartWithSlash($path): bool
283
    {
284
        return substr($path, 0, 1) == '/';
285
    }
286
287
    /**
288
     * @param $path
289
     * @return bool
290
     */
291
    public function isPathStartWithPointSlash($path): bool
292
    {
293
        return substr($path, 0, 2) == './';
294
    }
295
296
    /**
297
     * @param $path
298
     * @return bool
299
     */
300
    public function isPathStartWithTwoPointSlash($path): bool
301
    {
302
        return substr($path, 0, 3) == '../';
303
    }
304
}