PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.1.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.1.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 2 years ago Access 2 years ago Application 2 years ago Archive 2 years ago ArchiveProcessor 2 years ago Archiver 2 years ago AssetManager 2 years ago Auth 2 years ago Category 2 years ago Changes 2 years ago CliMulti 2 years ago Columns 2 years ago Concurrency 2 years ago Config 2 years ago Container 2 years ago CronArchive 2 years ago DataAccess 2 years ago DataFiles 2 years ago DataTable 2 years ago Db 2 years ago DeviceDetector 2 years ago Email 2 years ago Exception 2 years ago Http 2 years ago Intl 2 years ago Log 2 years ago Mail 2 years ago Measurable 2 years ago Menu 2 years ago Metrics 2 years ago Notification 2 years ago Period 2 years ago Plugin 2 years ago ProfessionalServices 2 years ago Report 2 years ago ReportRenderer 2 years ago Scheduler 2 years ago Segment 2 years ago Session 2 years ago Settings 2 years ago Tracker 2 years ago Translation 2 years ago Twig 2 years ago UpdateCheck 2 years ago Updater 2 years ago Updates 2 years ago Validators 2 years ago View 2 years ago ViewDataTable 2 years ago Visualization 2 years ago Widget 2 years ago .htaccess 2 years ago Access.php 2 years ago Archive.php 2 years ago ArchiveProcessor.php 2 years ago AssetManager.php 2 years ago Auth.php 2 years ago AuthResult.php 2 years ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 2 years ago CliMulti.php 2 years ago Common.php 2 years ago Config.php 2 years ago Console.php 2 years ago Context.php 2 years ago Cookie.php 2 years ago CronArchive.php 2 years ago DI.php 2 years ago DataArray.php 2 years ago DataTable.php 2 years ago Date.php 2 years ago Db.php 2 years ago DbHelper.php 2 years ago Development.php 2 years ago ErrorHandler.php 2 years ago EventDispatcher.php 2 years ago ExceptionHandler.php 2 years ago FileIntegrity.php 2 years ago Filechecks.php 2 years ago Filesystem.php 2 years ago FrontController.php 2 years ago Http.php 2 years ago IP.php 2 years ago Log.php 2 years ago LogDeleter.php 2 years ago Mail.php 2 years ago Metrics.php 2 years ago NoAccessException.php 2 years ago Nonce.php 2 years ago Notification.php 2 years ago NumberFormatter.php 2 years ago Option.php 2 years ago Period.php 2 years ago Piwik.php 2 years ago Plugin.php 2 years ago Profiler.php 2 years ago ProxyHeaders.php 2 years ago ProxyHttp.php 2 years ago QuickForm2.php 2 years ago RankingQuery.php 2 years ago ReportRenderer.php 2 years ago Request.php 2 years ago Segment.php 2 years ago Sequence.php 2 years ago Session.php 2 years ago SettingsPiwik.php 2 years ago SettingsServer.php 2 years ago Singleton.php 2 years ago Site.php 2 years ago SiteContentDetector.php 2 years ago SupportedBrowser.php 2 years ago TCPDF.php 2 years ago Theme.php 2 years ago Timer.php 2 years ago Tracker.php 2 years ago Twig.php 2 years ago Unzip.php 2 years ago UpdateCheck.php 2 years ago Updater.php 2 years ago UpdaterErrorException.php 2 years ago Updates.php 2 years ago Url.php 2 years ago UrlHelper.php 2 years ago Version.php 2 years ago View.php 2 years ago bootstrap.php 2 years ago dispatch.php 2 years ago testMinimumPhpVersion.php 2 years ago
UrlHelper.php
314 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 $uri = !empty($parsed['scheme']) ? $parsed['scheme'] . ':' . (!strcasecmp($parsed['scheme'], 'mailto') ? '' : '//') : '';
146 $uri .= !empty($parsed['user']) ? $parsed['user'] . (!empty($parsed['pass']) ? ':' . $parsed['pass'] : '') . '@' : '';
147 $uri .= !empty($parsed['host']) ? $parsed['host'] : '';
148 $uri .= !empty($parsed['port']) ? ':' . $parsed['port'] : '';
149 if (!empty($parsed['path'])) {
150 $uri .= !strncmp($parsed['path'], '/', 1) ? $parsed['path'] : (!empty($uri) ? '/' : '') . $parsed['path'];
151 }
152 $uri .= !empty($parsed['query']) ? '?' . $parsed['query'] : '';
153 $uri .= !empty($parsed['fragment']) ? '#' . $parsed['fragment'] : '';
154 return $uri;
155 }
156 /**
157 * Returns a URL query string as an array.
158 *
159 * @param string $urlQuery The query string, eg, `'?param1=value1&param2=value2'`.
160 * @return array eg, `array('param1' => 'value1', 'param2' => 'value2')`
161 * @api
162 */
163 public static function getArrayFromQueryString($urlQuery)
164 {
165 if (empty($urlQuery)) {
166 return array();
167 }
168 // TODO: this method should not use a cache. callers should instead have their own cache, configured through DI.
169 // one undesirable side effect of using a cache here, is that this method can now init the StaticContainer, which makes setting
170 // test environment for RequestCommand more complicated.
171 $cache = \Piwik\Cache::getTransientCache();
172 $cacheKey = 'arrayFromQuery' . $urlQuery;
173 if ($cache->contains($cacheKey)) {
174 return $cache->fetch($cacheKey);
175 }
176 if ($urlQuery[0] == '?') {
177 $urlQuery = substr($urlQuery, 1);
178 }
179 $separator = '&';
180 $urlQuery = $separator . $urlQuery;
181 // $urlQuery = str_replace(array('%20'), ' ', $urlQuery);
182 $referrerQuery = trim($urlQuery);
183 $values = explode($separator, $referrerQuery);
184 $nameToValue = array();
185 foreach ($values as $value) {
186 $pos = strpos($value, '=');
187 if ($pos !== false) {
188 $name = substr($value, 0, $pos);
189 $value = substr($value, $pos + 1);
190 if ($value === false) {
191 $value = '';
192 }
193 } else {
194 $name = $value;
195 $value = false;
196 }
197 if (!empty($name)) {
198 $name = \Piwik\Common::sanitizeInputValue($name);
199 }
200 if (!empty($value)) {
201 $value = \Piwik\Common::sanitizeInputValue($value);
202 }
203 // if array without indexes
204 $count = 0;
205 $tmp = preg_replace('/(\\[|%5b)(]|%5d)$/i', '', $name, -1, $count);
206 if (!empty($tmp) && $count) {
207 $name = $tmp;
208 if (isset($nameToValue[$name]) == false || is_array($nameToValue[$name]) == false) {
209 $nameToValue[$name] = array();
210 }
211 array_push($nameToValue[$name], $value);
212 } elseif (!empty($name)) {
213 $nameToValue[$name] = $value;
214 }
215 }
216 $cache->save($cacheKey, $nameToValue);
217 return $nameToValue;
218 }
219 /**
220 * Returns the value of a single query parameter from the supplied query string.
221 *
222 * @param string $urlQuery The query string.
223 * @param string $parameter The query parameter name to return.
224 * @return string|null Parameter value if found (can be the empty string!), null if not found.
225 * @api
226 */
227 public static function getParameterFromQueryString($urlQuery, $parameter)
228 {
229 $nameToValue = self::getArrayFromQueryString($urlQuery);
230 if (isset($nameToValue[$parameter])) {
231 return $nameToValue[$parameter];
232 }
233 return null;
234 }
235 /**
236 * Returns the path and query string of a URL.
237 *
238 * @param string $url The URL.
239 * @param array $additionalParamsToAdd If not empty the given parameters will be added to the query.
240 * @param bool $preserveAnchor If true then do not remove any #anchor from the url, default false
241 * @return string eg, `/test/index.php?module=CoreHome` if `$url` is `http://piwik.org/test/index.php?module=CoreHome`.
242 * @api
243 */
244 public static function getPathAndQueryFromUrl($url, array $additionalParamsToAdd = [], bool $preserveAnchor = false)
245 {
246 $parsedUrl = parse_url($url);
247 // If an anchor is included in the URL parse_url() will not split the anchor and query, so we do that there
248 if (isset($parsedUrl['fragment']) && strpos($parsedUrl['fragment'], '?') !== false) {
249 $parsedUrl['query'] = substr($parsedUrl['fragment'], strpos($parsedUrl['fragment'], '?') + 1);
250 $parsedUrl['fragment'] = substr($parsedUrl['fragment'], 0, strpos($parsedUrl['fragment'], '?'));
251 }
252 $result = '';
253 if (isset($parsedUrl['path'])) {
254 if (substr($parsedUrl['path'], 0, 1) == '/') {
255 $parsedUrl['path'] = substr($parsedUrl['path'], 1);
256 }
257 $result .= $parsedUrl['path'];
258 }
259 if ($preserveAnchor && isset($parsedUrl['fragment'])) {
260 $result .= '#' . $parsedUrl['fragment'];
261 }
262 if (isset($parsedUrl['query']) || count($additionalParamsToAdd)) {
263 $query = isset($parsedUrl['query']) ? $parsedUrl['query'] : '';
264 $query = self::addAdditionalParameters($query, $additionalParamsToAdd);
265 $result .= '?' . $query;
266 }
267 return $result;
268 }
269 /**
270 * Returns the query part from any valid url and adds additional parameters to the query part if needed.
271 *
272 * @param string $url Any url eg `"http://example.com/piwik/?foo=bar"`
273 * @param array $additionalParamsToAdd If not empty the given parameters will be added to the query.
274 *
275 * @return string eg. `"foo=bar&foo2=bar2"`
276 * @api
277 */
278 public static function getQueryFromUrl($url, array $additionalParamsToAdd = [])
279 {
280 $url = @parse_url($url);
281 $query = '';
282 if (!empty($url['query'])) {
283 $query .= $url['query'];
284 }
285 $query = self::addAdditionalParameters($query, $additionalParamsToAdd);
286 return $query;
287 }
288 /**
289 * Add an array of additional parameters to a query string
290 *
291 * @param string $query
292 * @param array $additionalParamsToAdd
293 *
294 * @return string
295 */
296 private static function addAdditionalParameters(string $query, array $additionalParamsToAdd) : string
297 {
298 if (!empty($additionalParamsToAdd)) {
299 if (!empty($query)) {
300 $query .= '&';
301 }
302 $query .= \Piwik\Url::getQueryStringFromParameters($additionalParamsToAdd);
303 }
304 return $query;
305 }
306 public static function getHostFromUrl($url)
307 {
308 if (!\Piwik\UrlHelper::isLookLikeUrl($url)) {
309 $url = "http://" . $url;
310 }
311 return parse_url($url, PHP_URL_HOST);
312 }
313 }
314