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 | /** |
||||
36 | * @var string |
||||
37 | */ |
||||
38 | private $pagePath; |
||||
39 | /** |
||||
40 | * @var string|null |
||||
41 | */ |
||||
42 | private $baseTag = null; |
||||
43 | /** |
||||
44 | * @var string|null |
||||
45 | */ |
||||
46 | private $starterPath = null; |
||||
47 | /** |
||||
48 | * @var array|false|int|string|null |
||||
49 | */ |
||||
50 | private $baseTagParsing; |
||||
51 | /** |
||||
52 | * @var array|false|int|string|null |
||||
53 | */ |
||||
54 | private $pagePathParsing; |
||||
55 | /** |
||||
56 | * @var string |
||||
57 | */ |
||||
58 | private $domain; |
||||
59 | /** |
||||
60 | * @var string |
||||
61 | */ |
||||
62 | private $scheme; |
||||
63 | |||||
64 | /** |
||||
65 | * ConvertToAbsolutePath constructor. |
||||
66 | * @param $pagePath |
||||
67 | * @throws \Exception |
||||
68 | */ |
||||
69 | public function __construct($pagePath) |
||||
70 | { |
||||
71 | if ($this->isCorrectUrl(parse_url($pagePath))) { |
||||
72 | $this->setPagePath($pagePath); |
||||
73 | }else{ |
||||
74 | throw new \Exception('path is not correct url'); |
||||
75 | } |
||||
76 | } |
||||
77 | |||||
78 | /** |
||||
79 | * @inheritDoc |
||||
80 | */ |
||||
81 | public function convert($path) |
||||
82 | { |
||||
83 | // Skip converting if the relative url like http://... or android-app://... etc. |
||||
84 | if ($this->isPathAbsoluteOrForAnotherApp($path)) { |
||||
85 | return $this->checkPathIsAbsoluteOrForAnotherApp($path); |
||||
86 | } |
||||
87 | // Treat path as invalid if it is like javascript:... etc. |
||||
88 | if ($this->isPathJavaScript($path)) { |
||||
89 | return ''; |
||||
90 | } |
||||
91 | // Convert //www.google.com to http://www.google.com |
||||
92 | if ($this->isPathWithoutScheme($path)) { |
||||
93 | return 'http:' . $path; |
||||
94 | } |
||||
95 | |||||
96 | // If the path is a fragment or query string, |
||||
97 | // it will be appended to the base url |
||||
98 | if ($this->isHaveQueryOrFragment($path)) { |
||||
99 | return $this->getStarterPath() . $path; |
||||
100 | } |
||||
101 | // Treat paths with doc root, i.e, /about |
||||
102 | if ($this->isPathStartWithSlash($path)) { |
||||
103 | return $this->onlySitePath($this->getStarterPath()) . $path; |
||||
104 | } |
||||
105 | // For paths like ./foo, it will be appended to the furthest directory |
||||
106 | if ($this->isPathStartWithPointSlash($path)) { |
||||
107 | return $this->uptoLastDir($this->getStarterPath()) . substr($path, 2); |
||||
108 | } |
||||
109 | // Convert paths like ../foo or ../../bar |
||||
110 | if ($this->isPathStartWithTwoPointSlash($path)) { |
||||
111 | return (new RemovePathWithPointPointSlash($this, $path))->compute(); |
||||
112 | } |
||||
113 | if (empty($path)) { |
||||
114 | return $this->getPagePath(); |
||||
115 | } |
||||
116 | // else |
||||
117 | return $this->uptoLastDir($this->getStarterPath()) . $path; |
||||
118 | } |
||||
119 | |||||
120 | public function onlySitePath($url) { |
||||
121 | $parseUrl = parse_url($url); |
||||
122 | if ($this->isCorrectUrl($parseUrl)) { |
||||
123 | return $parseUrl['scheme'] . '://' . $parseUrl['host']; |
||||
124 | } elseif(isset($parseUrl['host'])) { |
||||
125 | return $parseUrl['host']; |
||||
126 | } else { |
||||
127 | return ''; |
||||
128 | } |
||||
129 | } |
||||
130 | |||||
131 | // Get the path with last directory |
||||
132 | // http://example.com/some/fake/path/page.html => http://example.com/some/fake/path/ |
||||
133 | public function upToLastDir($url) { |
||||
134 | $parseUrl = parse_url($url); |
||||
135 | $path = ''; |
||||
136 | if(isset($parseUrl['path'])) { |
||||
137 | $path = preg_replace('/\/([^\/]+)$/i', '', $parseUrl['path']); |
||||
138 | } |
||||
139 | return rtrim($parseUrl['scheme'] . '://' . $parseUrl['host'] . $path, '/') . '/'; |
||||
140 | } |
||||
141 | |||||
142 | |||||
143 | public function getPagePath() |
||||
144 | { |
||||
145 | return $this->pagePath; |
||||
146 | } |
||||
147 | |||||
148 | /** |
||||
149 | * @param string $pagePath |
||||
150 | */ |
||||
151 | public function setPagePath(string $pagePath): void |
||||
152 | { |
||||
153 | $this->pagePath = $pagePath; |
||||
154 | } |
||||
155 | |||||
156 | |||||
157 | public function getBaseTag() |
||||
158 | { |
||||
159 | return $this->baseTag; |
||||
160 | } |
||||
161 | |||||
162 | /** |
||||
163 | * @param string $baseTag |
||||
164 | */ |
||||
165 | public function setBaseTag(string $baseTag): void |
||||
166 | { |
||||
167 | $this->baseTag = $baseTag; |
||||
168 | } |
||||
169 | |||||
170 | /** |
||||
171 | * @return string |
||||
172 | */ |
||||
173 | public function getStarterPath(): string |
||||
174 | { |
||||
175 | if ($this->starterPath===null) { |
||||
176 | if ($this->getBaseTag() === null) { |
||||
177 | $this->starterPath =$this->getPagePath(); |
||||
178 | } elseif (array_key_exists('scheme', $this->getBaseTagParsing())) { |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
179 | $this->starterPath = $this->getBaseTag() ; |
||||
180 | } else { |
||||
181 | $this->starterPath = $this->getPagePathParsing()['scheme'] . '://' . $this->getPagePathParsing()['host'] . |
||||
182 | '/' . trim($this->getBaseTag(), '/') . '/'; |
||||
183 | } |
||||
184 | } |
||||
185 | return $this->starterPath; |
||||
186 | } |
||||
187 | |||||
188 | public function getDomain() |
||||
189 | { |
||||
190 | if ($this->domain === null) { |
||||
191 | if ($this->getBaseTag() === null) { |
||||
192 | $this->domain = $this->getPagePathParsing()['host'] . '/'; |
||||
193 | }elseif (array_key_exists('scheme', $this->getBaseTagParsing())){ |
||||
0 ignored issues
–
show
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
![]() |
|||||
194 | $this->domain = $this->getBaseTagParsing()['host'] . '/'; |
||||
195 | }else { |
||||
196 | $this->domain = $this->getPagePathParsing()['host'] . '/'; |
||||
197 | } |
||||
198 | } |
||||
199 | return $this->domain; |
||||
200 | } |
||||
201 | |||||
202 | public function getScheme() |
||||
203 | { |
||||
204 | if ($this->scheme === null) { |
||||
205 | if ($this->getBaseTag() === null) { |
||||
206 | $this->scheme = $this->getPagePathParsing()['scheme']; |
||||
207 | }elseif (array_key_exists('scheme', $this->getBaseTagParsing())){ |
||||
0 ignored issues
–
show
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
![]() |
|||||
208 | $this->scheme = $this->getBaseTagParsing()['scheme']; |
||||
209 | }else { |
||||
210 | $this->scheme = $this->getPagePathParsing()['scheme']; |
||||
211 | } |
||||
212 | } |
||||
213 | return $this->scheme; |
||||
214 | } |
||||
215 | |||||
216 | public function getBaseTagParsing() |
||||
217 | { |
||||
218 | if ($this->baseTagParsing == null) { |
||||
219 | if (is_string($this->getBaseTag())) { |
||||
220 | $this->baseTagParsing = parse_url($this->getBaseTag()); |
||||
221 | } else { |
||||
222 | $this->baseTagParsing = []; |
||||
223 | } |
||||
224 | } |
||||
225 | return $this->baseTagParsing; |
||||
226 | } |
||||
227 | |||||
228 | public function getPagePathParsing() |
||||
229 | { |
||||
230 | if ($this->pagePathParsing == null) { |
||||
231 | $this->pagePathParsing = parse_url($this->getPagePath()); |
||||
232 | } |
||||
233 | return $this->pagePathParsing; |
||||
234 | } |
||||
235 | |||||
236 | /** |
||||
237 | * @param $path |
||||
238 | * @return bool |
||||
239 | */ |
||||
240 | public function isHaveQueryOrFragment($path): bool |
||||
241 | { |
||||
242 | return substr($path, 0, 1) == '#' || substr($path, 0, 1) == '?'; |
||||
243 | } |
||||
244 | |||||
245 | /** |
||||
246 | * @param $parseUrl |
||||
247 | * @return bool |
||||
248 | */ |
||||
249 | public function isCorrectUrl($parseUrl): bool |
||||
250 | { |
||||
251 | return isset($parseUrl['scheme']) AND isset($parseUrl['host']); |
||||
252 | } |
||||
253 | |||||
254 | /** |
||||
255 | * @param $path |
||||
256 | * @return string |
||||
257 | */ |
||||
258 | public function checkPathIsAbsoluteOrForAnotherApp($path): string |
||||
259 | { |
||||
260 | if (preg_match('/services:\/\//i', $path)) { |
||||
261 | return ''; |
||||
262 | } |
||||
263 | if (preg_match('/whatsapp:\/\//i', $path)) { |
||||
264 | return ''; |
||||
265 | } |
||||
266 | if (preg_match('/tel:/i', $path)) { |
||||
267 | return ''; |
||||
268 | } |
||||
269 | return $path; |
||||
270 | } |
||||
271 | |||||
272 | /** |
||||
273 | * @param $path |
||||
274 | * @return false|int |
||||
275 | */ |
||||
276 | public function isPathAbsoluteOrForAnotherApp($path) |
||||
277 | { |
||||
278 | return preg_match('/[a-z0-9-]{1,}(:\/\/)/i', $path); |
||||
279 | } |
||||
280 | |||||
281 | /** |
||||
282 | * @param $path |
||||
283 | * @return false|int |
||||
284 | */ |
||||
285 | public function isPathJavaScript($path) |
||||
286 | { |
||||
287 | return preg_match('/^[a-zA-Z]{0,}:[^\/]{0,1}/i', $path); |
||||
288 | } |
||||
289 | |||||
290 | /** |
||||
291 | * @param $path |
||||
292 | * @return bool |
||||
293 | */ |
||||
294 | public function isPathWithoutScheme($path): bool |
||||
295 | { |
||||
296 | return substr($path, 0, 2) == '//'; |
||||
297 | } |
||||
298 | |||||
299 | /** |
||||
300 | * @param $path |
||||
301 | * @return bool |
||||
302 | */ |
||||
303 | public function isPathStartWithSlash($path): bool |
||||
304 | { |
||||
305 | return substr($path, 0, 1) == '/'; |
||||
306 | } |
||||
307 | |||||
308 | /** |
||||
309 | * @param $path |
||||
310 | * @return bool |
||||
311 | */ |
||||
312 | public function isPathStartWithPointSlash($path): bool |
||||
313 | { |
||||
314 | return substr($path, 0, 2) == './'; |
||||
315 | } |
||||
316 | |||||
317 | /** |
||||
318 | * @param $path |
||||
319 | * @return bool |
||||
320 | */ |
||||
321 | public function isPathStartWithTwoPointSlash($path): bool |
||||
322 | { |
||||
323 | return substr($path, 0, 3) == '../'; |
||||
324 | } |
||||
325 | } |