PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.2.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.2.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / UrlHelper.php
matomo / app / core Last commit date
API 1 year ago Access 1 year ago Application 1 year ago Archive 1 year ago ArchiveProcessor 1 year ago Archiver 2 years ago AssetManager 1 year ago Auth 1 year ago Category 2 years ago Changes 1 year ago CliMulti 1 year ago Columns 1 year ago Concurrency 1 year ago Config 1 year ago Container 1 year ago CronArchive 1 year ago DataAccess 1 year ago DataFiles 2 years ago DataTable 1 year ago Db 1 year ago DeviceDetector 1 year ago Email 2 years ago Exception 1 year ago Http 1 year ago Intl 1 year ago Log 2 years ago Mail 1 year ago Measurable 1 year ago Menu 1 year ago Metrics 1 year ago Notification 1 year ago Period 1 year ago Plugin 1 year ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 1 year ago Scheduler 1 year ago Segment 1 year ago Session 1 year ago Settings 1 year ago Tracker 1 year ago Translation 1 year ago Twig 1 year ago UpdateCheck 1 year ago Updater 1 year ago Updates 1 year ago Validators 1 year ago View 1 year ago ViewDataTable 1 year ago Visualization 1 year ago Widget 1 year ago .htaccess 2 years ago Access.php 1 year ago Archive.php 1 year ago ArchiveProcessor.php 1 year ago AssetManager.php 1 year ago Auth.php 2 years ago AuthResult.php 2 years ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 1 year ago CliMulti.php 1 year ago Common.php 1 year ago Config.php 1 year ago Console.php 1 year ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 1 year ago DI.php 1 year ago DataArray.php 1 year ago DataTable.php 1 year ago Date.php 1 year ago Db.php 1 year ago DbHelper.php 1 year ago Development.php 1 year ago ErrorHandler.php 1 year ago EventDispatcher.php 1 year ago ExceptionHandler.php 1 year ago FileIntegrity.php 1 year ago Filechecks.php 1 year ago Filesystem.php 1 year ago FrontController.php 1 year ago Http.php 1 year ago IP.php 1 year ago Log.php 2 years ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 1 year ago NoAccessException.php 2 years ago Nonce.php 1 year ago Notification.php 1 year ago NumberFormatter.php 1 year ago Option.php 1 year ago Period.php 1 year ago Piwik.php 1 year ago Plugin.php 1 year ago Process.php 1 year ago Profiler.php 1 year ago ProxyHeaders.php 2 years ago ProxyHttp.php 1 year ago QuickForm2.php 1 year ago RankingQuery.php 1 year ago ReportRenderer.php 1 year ago Request.php 1 year ago Segment.php 1 year ago Sequence.php 2 years ago Session.php 1 year ago SettingsPiwik.php 1 year ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 1 year ago SiteContentDetector.php 1 year ago SupportedBrowser.php 2 years ago TCPDF.php 1 year ago Theme.php 1 year ago Timer.php 2 years ago Tracker.php 1 year ago Twig.php 1 year ago Unzip.php 1 year ago UpdateCheck.php 1 year ago Updater.php 1 year ago UpdaterErrorException.php 2 years ago Updates.php 1 year ago Url.php 1 year ago UrlHelper.php 1 year ago Version.php 1 year ago View.php 1 year ago bootstrap.php 1 year ago dispatch.php 2 years ago testMinimumPhpVersion.php 2 years ago
UrlHelper.php
319 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik;
10
11 use Piwik\Container\StaticContainer;
12 use Piwik\Intl\Data\Provider\RegionDataProvider;
13 /**
14 * Contains less commonly needed URL helper methods.
15 *
16 */
17 class UrlHelper
18 {
19 private static $validLinkProtocols = ['http', 'https', 'tel', 'sms', 'mailto', 'callto'];
20 /**
21 * Checks if a string matches/is equal to one of the patterns/strings.
22 *
23 * @static
24 * @param $test String to test.
25 * @param $patterns Array of strings or regexs.
26 *
27 * @return bool true if $test matches or is equal to one of the regex/string in $patterns, false otherwise.
28 */
29 protected static function inArrayMatchesRegex($test, $patterns) : bool
30 {
31 foreach ($patterns as $val) {
32 if (@preg_match($val, '') === \false) {
33 if (strcasecmp($val, $test) === 0) {
34 return \true;
35 }
36 } else {
37 if (preg_match($val, $test) === 1) {
38 return \true;
39 }
40 }
41 }
42 return \false;
43 }
44 /**
45 * Converts an array of query parameter name/value mappings into a query string.
46 * Parameters that are in `$parametersToExclude` will not appear in the result.
47 *
48 * @static
49 * @param $queryParameters Array of query parameters, eg, `array('site' => '0', 'date' => '2012-01-01')`.
50 * @param $parametersToExclude Array of query parameter names that shouldn't be
51 * in the result query string, eg, `array('date', 'period')`.
52 * @return string A query string, eg, `"?site=0"`.
53 * @api
54 */
55 public static function getQueryStringWithExcludedParameters($queryParameters, $parametersToExclude)
56 {
57 $validQuery = '';
58 $separator = '&';
59 foreach ($queryParameters as $name => $value) {
60 // decode encoded square brackets
61 $name = str_replace(array('%5B', '%5D'), array('[', ']'), $name);
62 if (!self::inArrayMatchesRegex(strtolower($name), $parametersToExclude)) {
63 if (is_array($value)) {
64 foreach ($value as $param) {
65 if ($param === \false) {
66 $validQuery .= $name . '[]' . $separator;
67 } else {
68 $validQuery .= $name . '[]=' . $param . $separator;
69 }
70 }
71 } elseif ($value === \false) {
72 $validQuery .= $name . $separator;
73 } else {
74 $validQuery .= $name . '=' . $value . $separator;
75 }
76 }
77 }
78 $validQuery = substr($validQuery, 0, -strlen($separator));
79 return $validQuery;
80 }
81 /**
82 * Reduce URL to more minimal form. 2 letter country codes are
83 * replaced by '{}', while other parts are simply removed.
84 *
85 * Examples:
86 * www.example.com -> example.com
87 * search.example.com -> example.com
88 * m.example.com -> example.com
89 * de.example.com -> {}.example.com
90 * example.de -> example.{}
91 * example.co.uk -> example.{}
92 *
93 * @param string $url
94 * @return string
95 */
96 public static function getLossyUrl($url)
97 {
98 static $countries;
99 if (!isset($countries)) {
100 /** @var RegionDataProvider $regionDataProvider */
101 $regionDataProvider = StaticContainer::get('Piwik\\Intl\\Data\\Provider\\RegionDataProvider');
102 $countries = implode('|', array_keys($regionDataProvider->getCountryList(\true)));
103 }
104 return preg_replace(array('/^(w+[0-9]*|search)\\./', '/(^|\\.)m\\./', '/(\\.(com|org|net|co|it|edu))?\\.(' . $countries . ')(\\/|$)/', '/(^|\\.)(' . $countries . ')\\./'), array('', '$1', '.{}$4', '$1{}.'), $url);
105 }
106 /**
107 * Returns true if the string passed may be a URL ie. it starts with protocol://.
108 * We don't need a precise test here because the value comes from the website
109 * tracked source code and the URLs may look very strange.
110 *
111 * @api
112 * @param string $url
113 * @return bool
114 */
115 public static function isLookLikeUrl($url)
116 {
117 return $url && preg_match('~^(([[:alpha:]][[:alnum:]+.-]*)?:)?//(.*)$~D', $url, $matches) !== 0 && strlen($matches[3]) > 0 && !preg_match('/^(javascript:|vbscript:|data:)/i', $matches[1]);
118 }
119 public static function isLookLikeSafeUrl($url)
120 {
121 if (preg_match('/[\\x00-\\x1F\\x7F]/', $url)) {
122 return \false;
123 }
124 if (strpos($url, ':') === \false) {
125 return \true;
126 }
127 $protocol = explode(':', $url, 2)[0];
128 return preg_match('/^(' . implode('|', self::$validLinkProtocols) . ')$/i', $protocol);
129 }
130 /**
131 * Returns a URL created from the result of the [parse_url](http://php.net/manual/en/function.parse-url.php)
132 * function.
133 *
134 * Copied from the PHP comments at [http://php.net/parse_url](http://php.net/parse_url).
135 *
136 * @param array $parsed Result of [parse_url](http://php.net/manual/en/function.parse-url.php).
137 * @return false|string The URL or `false` if `$parsed` isn't an array.
138 * @api
139 */
140 public static function getParseUrlReverse($parsed)
141 {
142 if (!is_array($parsed)) {
143 return \false;
144 }
145 // According to RFC 1738, the chars ':', '@' and '/' need to be encoded in username or password part of an url
146 // We also encode '\' as a username or password containing that char, might be handled incorrectly by browsers
147 $escapeSpecialChars = function ($value) {
148 return str_replace([':', '@', '/', '\\'], [urlencode(':'), urlencode('@'), urlencode('/'), urlencode('\\')], $value);
149 };
150 $uri = !empty($parsed['scheme']) ? $parsed['scheme'] . ':' . (!strcasecmp($parsed['scheme'], 'mailto') ? '' : '//') : '';
151 $uri .= !empty($parsed['user']) ? $escapeSpecialChars($parsed['user']) . (!empty($parsed['pass']) ? ':' . $escapeSpecialChars($parsed['pass']) : '') . '@' : '';
152 $uri .= !empty($parsed['host']) ? $parsed['host'] : '';
153 $uri .= !empty($parsed['port']) ? ':' . $parsed['port'] : '';
154 if (!empty($parsed['path'])) {
155 $uri .= !strncmp($parsed['path'], '/', 1) ? $parsed['path'] : (!empty($uri) ? '/' : '') . $parsed['path'];
156 }
157 $uri .= !empty($parsed['query']) ? '?' . $parsed['query'] : '';
158 $uri .= !empty($parsed['fragment']) ? '#' . $parsed['fragment'] : '';
159 return $uri;
160 }
161 /**
162 * Returns a URL query string as an array.
163 *
164 * @param string $urlQuery The query string, eg, `'?param1=value1&param2=value2'`.
165 * @return array eg, `array('param1' => 'value1', 'param2' => 'value2')`
166 * @api
167 */
168 public static function getArrayFromQueryString($urlQuery)
169 {
170 if (empty($urlQuery)) {
171 return array();
172 }
173 // TODO: this method should not use a cache. callers should instead have their own cache, configured through DI.
174 // one undesirable side effect of using a cache here, is that this method can now init the StaticContainer, which makes setting
175 // test environment for RequestCommand more complicated.
176 $cache = \Piwik\Cache::getTransientCache();
177 $cacheKey = 'arrayFromQuery' . $urlQuery;
178 if ($cache->contains($cacheKey)) {
179 return $cache->fetch($cacheKey);
180 }
181 if ($urlQuery[0] == '?') {
182 $urlQuery = substr($urlQuery, 1);
183 }
184 $separator = '&';
185 $urlQuery = $separator . $urlQuery;
186 // $urlQuery = str_replace(array('%20'), ' ', $urlQuery);
187 $referrerQuery = trim($urlQuery);
188 $values = explode($separator, $referrerQuery);
189 $nameToValue = array();
190 foreach ($values as $value) {
191 $pos = strpos($value, '=');
192 if ($pos !== \false) {
193 $name = substr($value, 0, $pos);
194 $value = substr($value, $pos + 1);
195 if ($value === \false) {
196 $value = '';
197 }
198 } else {
199 $name = $value;
200 $value = \false;
201 }
202 if (!empty($name)) {
203 $name = \Piwik\Common::sanitizeInputValue($name);
204 }
205 if (!empty($value)) {
206 $value = \Piwik\Common::sanitizeInputValue($value);
207 }
208 // if array without indexes
209 $count = 0;
210 $tmp = preg_replace('/(\\[|%5b)(]|%5d)$/i', '', $name, -1, $count);
211 if (!empty($tmp) && $count) {
212 $name = $tmp;
213 if (isset($nameToValue[$name]) == \false || is_array($nameToValue[$name]) == \false) {
214 $nameToValue[$name] = array();
215 }
216 array_push($nameToValue[$name], $value);
217 } elseif (!empty($name)) {
218 $nameToValue[$name] = $value;
219 }
220 }
221 $cache->save($cacheKey, $nameToValue);
222 return $nameToValue;
223 }
224 /**
225 * Returns the value of a single query parameter from the supplied query string.
226 *
227 * @param string $urlQuery The query string.
228 * @param string $parameter The query parameter name to return.
229 * @return string|null Parameter value if found (can be the empty string!), null if not found.
230 * @api
231 */
232 public static function getParameterFromQueryString($urlQuery, $parameter)
233 {
234 $nameToValue = self::getArrayFromQueryString($urlQuery);
235 if (isset($nameToValue[$parameter])) {
236 return $nameToValue[$parameter];
237 }
238 return null;
239 }
240 /**
241 * Returns the path and query string of a URL.
242 *
243 * @param string $url The URL.
244 * @param array $additionalParamsToAdd If not empty the given parameters will be added to the query.
245 * @param bool $preserveAnchor If true then do not remove any #anchor from the url, default false
246 * @return string eg, `/test/index.php?module=CoreHome` if `$url` is `http://piwik.org/test/index.php?module=CoreHome`.
247 * @api
248 */
249 public static function getPathAndQueryFromUrl($url, array $additionalParamsToAdd = [], bool $preserveAnchor = \false)
250 {
251 $parsedUrl = parse_url($url);
252 // If an anchor is included in the URL parse_url() will not split the anchor and query, so we do that there
253 if (isset($parsedUrl['fragment']) && strpos($parsedUrl['fragment'], '?') !== \false) {
254 $parsedUrl['query'] = substr($parsedUrl['fragment'], strpos($parsedUrl['fragment'], '?') + 1);
255 $parsedUrl['fragment'] = substr($parsedUrl['fragment'], 0, strpos($parsedUrl['fragment'], '?'));
256 }
257 $result = '';
258 if (isset($parsedUrl['path'])) {
259 if (substr($parsedUrl['path'], 0, 1) == '/') {
260 $parsedUrl['path'] = substr($parsedUrl['path'], 1);
261 }
262 $result .= $parsedUrl['path'];
263 }
264 if ($preserveAnchor && isset($parsedUrl['fragment'])) {
265 $result .= '#' . $parsedUrl['fragment'];
266 }
267 if (isset($parsedUrl['query']) || count($additionalParamsToAdd)) {
268 $query = isset($parsedUrl['query']) ? $parsedUrl['query'] : '';
269 $query = self::addAdditionalParameters($query, $additionalParamsToAdd);
270 $result .= '?' . $query;
271 }
272 return $result;
273 }
274 /**
275 * Returns the query part from any valid url and adds additional parameters to the query part if needed.
276 *
277 * @param string $url Any url eg `"http://example.com/piwik/?foo=bar"`
278 * @param array $additionalParamsToAdd If not empty the given parameters will be added to the query.
279 *
280 * @return string eg. `"foo=bar&foo2=bar2"`
281 * @api
282 */
283 public static function getQueryFromUrl($url, array $additionalParamsToAdd = [])
284 {
285 $url = @parse_url($url);
286 $query = '';
287 if (!empty($url['query'])) {
288 $query .= $url['query'];
289 }
290 $query = self::addAdditionalParameters($query, $additionalParamsToAdd);
291 return $query;
292 }
293 /**
294 * Add an array of additional parameters to a query string
295 *
296 * @param string $query
297 * @param array $additionalParamsToAdd
298 *
299 * @return string
300 */
301 private static function addAdditionalParameters(string $query, array $additionalParamsToAdd) : string
302 {
303 if (!empty($additionalParamsToAdd)) {
304 if (!empty($query)) {
305 $query .= '&';
306 }
307 $query .= \Piwik\Url::getQueryStringFromParameters($additionalParamsToAdd);
308 }
309 return $query;
310 }
311 public static function getHostFromUrl($url)
312 {
313 if (!\Piwik\UrlHelper::isLookLikeUrl($url)) {
314 $url = "http://" . $url;
315 }
316 return parse_url($url, \PHP_URL_HOST);
317 }
318 }
319