URIUtil.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\util;
12 
13 /**
14  * URIUtil provides support for uri manipulation.
15  *
16  * @author ingo herwig <ingo@wemove.com>
17  */
18 class URIUtil {
19 
20  /**
21  * Convert an absolute URI to a relative
22  * code from http://www.webmasterworld.com/forum88/334.htm
23  * @param $absUri Absolute URI at which the path should end, may have a trailing filename
24  * @param $base Absolute URI from which the relative should start
25  * @return String
26  */
27  public static function makeRelative($absUri, $base) {
28  // normalize slashes and remove drive names
29  list($absUri, $base) = self::normalizePaths(
30  self::removeProtocols(self::normalizeSlashes([$absUri, $base])));
31 
32  // add slash to base if missing
33  if (!preg_match('/\/$/', $base)) {
34  $base .= '/';
35  }
36  $absArray = explode('/', $absUri);
37  $baseArray = explode('/', $base);
38 
39  // remove trailing file names
40  $fileName = '';
41  if (strrpos($absUri, '/') !== strlen($absUri)) {
42  $fileName = array_pop($absArray);
43  }
44  if (strrpos($base, '/') !== strlen($base)) {
45  array_pop($baseArray);
46  }
47 
48  // ignore common path
49  while (sizeof($absArray) > 0 && sizeof($baseArray) > 0 && $absArray[0] == $baseArray[0]) {
50  array_shift($absArray);
51  array_shift($baseArray);
52  }
53 
54  // construct connecting path
55  $relUri = self::normalizePaths(str_repeat('../', sizeof($baseArray)).join('/', $absArray).'/'.$fileName);
56  return $relUri;
57  }
58 
59  /**
60  * Convert a relative URI to an absolute
61  * code from http://99webtools.com/relative-path-into-absolute-url.php
62  * @param $relUri URI relative to base
63  * @param $base Absolute URI
64  * @return String
65  */
66  public static function makeAbsolute($relUri, $base) {
67  list($relUri, $base) = self::normalizeSlashes([$relUri, $base]);
68 
69  // return if already absolute URL
70  if (parse_url($relUri, PHP_URL_SCHEME) != '') {
71  return $relUri;
72  }
73  // add slash to base if missing
74  if (!preg_match('/\/$/', $base)) {
75  $base .= '/';
76  }
77  $firstChar = (strlen($relUri) > 0) ? substr($relUri, 0, 1) : '';
78  // queries and anchors
79  if ($firstChar == '#' || $firstChar == '?') {
80  return $base.$relUri;
81  }
82  // parse base URL and convert to local variables: $scheme, $host, $path
83  extract(parse_url($base));
84  $scheme = !isset($scheme) ? '' : $scheme.'://';
85  $host = !isset($host) ? '' : $host;
86  $path = !isset($path) ? '' : $path;
87  // remove non-directory element from path
88  $path = preg_replace('#/[^/]*$#', '', $path);
89  // destroy path if relative url points to root
90  if ($firstChar == '/') {
91  $path = '';
92  }
93  // dirty absolute URL
94  $abs = "$host$path/$relUri";
95  // normalize
96  $abs = self::normalizePaths($abs);
97  // absolute URL is ready!
98  return $scheme.$abs;
99  }
100 
101  /**
102  * Translate a relative URI from one location to the script location.
103  * For example if a file path is stored relative to location A and should be
104  * translated to the script URI (location B), use
105  * URIUtil::translate($filepathAsSeenFromA, $pathFromBtoA)
106  * @param $pathFromA Relative URI to translate as seen from base
107  * @param $pathFromScriptToA Base URI
108  * @return Associative array with keys 'absolute' and 'relative'
109  * and the absolute and relative URI (as seen from the executed script) as values
110  */
111  public static function translate($pathFromA, $pathFromScriptToA) {
112  list($pathFromA, $pathFromScriptToA) = self::normalizeSlashes([$pathFromA, $pathFromScriptToA]);
113 
114  $self = self::getProtocolStr().$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
115  $path = dirname($self).'/';
116  $absUrl = self::makeAbsolute($pathFromA, $path.$pathFromScriptToA);
117  $relUrl = self::makeRelative($absUrl, $path);
118 
119  return ['absolute' => $absUrl, 'relative' => $relUrl];
120  }
121 
122  /**
123  * Check if an url is available (HTTP-Code: 200)
124  * @note requires cURL library
125  * @param $url The url to check
126  * @param $timeout The timeout in seconds (default: 5)
127  * @return Boolean
128  */
129  public static function validateUrl($url, $timeout=5) {
130  $urlParts = @parse_url($url);
131  // check local relative url
132  if (empty($urlParts["host"])) {
133  $fh = @fopen($url, "r");
134  return ($fh !== false);
135  }
136 
137  // check remote url
138  $ch = curl_init();
139  curl_setopt($ch, CURLOPT_URL, $url);
140  curl_setopt($ch, CURLOPT_HEADER, true);
141  curl_setopt($ch, CURLOPT_NOBODY, true);
142  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
143  curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
144  $r = curl_exec($ch);
145  $headers = split("\n", $r);
146 
147  preg_match('/.+ ([0-9]{3}) .+/', $headers[0], $matches);
148  return (intval($matches[1]) < 400);
149  }
150 
151  /*
152  * Determine, if the script is served via HTTPS
153  * @return Boolean
154  */
155  public static function isHttps() {
156  $isHttps =
157  $_SERVER['HTTP_X_FORWARDED_PROTO'] ??
158  $_SERVER['REQUEST_SCHEME'] ??
159  $_SERVER['HTTPS'] ??
160  null
161  ;
162  return $isHttps && (strcasecmp('on', $isHttps) == 0 || strcasecmp('https', $isHttps) == 0);
163  }
164 
165  /*
166  * Get the protocol string (http:// or https://)
167  * @return String
168  */
169  public static function getProtocolStr() {
170  return self::isHttps() ? 'https://' : 'http://';
171  }
172 
173  /**
174  * Normalize slashes
175  * @param $paths Path to normalize or array of paths
176  */
177  private static function normalizeSlashes($paths) {
178  return preg_replace(["/\\\\/"], ['/'], $paths);
179  }
180 
181  /**
182  * Remove protocols
183  * @param $paths Path to normalize or array of paths
184  */
185  private static function removeProtocols($paths) {
186  return preg_replace(["/^[^:]{1}:/"], [''], $paths);
187  }
188 
189  /**
190  * Normalize paths (replace '//' or '/./' or '/foo/../' with '/')
191  * @param $paths Path to normalize or array of paths
192  */
193  private static function normalizePaths($paths) {
194  $re = ['#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#'];
195  for ($n=1; $n>0; $paths=preg_replace($re, '/', $paths, -1, $n)) {}
196  return $paths;
197  }
198 }
199 ?>
static makeAbsolute($relUri, $base)
Convert a relative URI to an absolute code from http://99webtools.com/relative-path-into-absolute-url...
Definition: URIUtil.php:66
static translate($pathFromA, $pathFromScriptToA)
Translate a relative URI from one location to the script location.
Definition: URIUtil.php:111
URIUtil provides support for uri manipulation.
Definition: URIUtil.php:18
static validateUrl($url, $timeout=5)
Check if an url is available (HTTP-Code: 200)
Definition: URIUtil.php:129
Utility classes.
Definition: namespaces.php:97
static getProtocolStr()
Definition: URIUtil.php:169
static makeRelative($absUri, $base)
Convert an absolute URI to a relative code from http://www.webmasterworld.com/forum88/334....
Definition: URIUtil.php:27