83 lines
3 KiB
PHP
83 lines
3 KiB
PHP
|
<?php
|
||
|
function sitematch($key,$site){
|
||
|
// Add double slashes to key and site if no scheme is set.
|
||
|
// Basically: if no double slashes present before any dots,shashes or @s.
|
||
|
if(!\preg_match_all('#^[^./@]*?//#',$key )) {
|
||
|
$key = "//".$key;
|
||
|
}
|
||
|
if(!\preg_match_all('#^[^./@]*?//#',$site)) {
|
||
|
$site = "//".$site;
|
||
|
}
|
||
|
// Use parse_url() to split path and host.
|
||
|
$keyurl = (object)\parse_url($key);
|
||
|
$siteurl = (object)\parse_url($site);
|
||
|
|
||
|
// No match if host is empty on key or site
|
||
|
if (empty($keyurl->host) || empty($siteurl->host)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ($keyurl->host == "*") {
|
||
|
// * matches all
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// First match the host part.
|
||
|
$keyparts = \array_reverse(\explode(".",$keyurl->host));
|
||
|
$siteparts = \array_reverse(\explode(".",$siteurl->host));
|
||
|
|
||
|
// Trim starting www from both parts, since site.domain and www.site.domain should be treated as the same.
|
||
|
if (($x = \array_pop($keyparts)) != "www") {\array_push($keyparts,$x);}
|
||
|
if (($x = \array_pop($siteparts)) != "www") {\array_push($siteparts,$x);}
|
||
|
|
||
|
for ($i = 0; $i < count($keyparts); $i++) {
|
||
|
// No match if the site does not have a part, but the key does. Unless the key part is *
|
||
|
if (!isset($siteparts[$i]) ) {
|
||
|
if($keyparts[$i] != "*") {
|
||
|
return false;
|
||
|
} else {
|
||
|
$i++; //increment $i by one before break, to make sure the comparison following this loop holds.
|
||
|
break; // Stop comparison. Host part matches.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now do a proper case insensitive check for matching.
|
||
|
// Uses fnmatch to easily handle shell type wildcards.
|
||
|
if ( ! \fnmatch($keyparts[$i],$siteparts[$i],\FNM_CASEFOLD)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
// Fail if the site has a deeper subdomain than the key, unless the deepest key subdomain is *
|
||
|
if ($keyparts[$i-1] != '*' && count($siteparts) > ($i)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// If we made it here then the host part matches. Now check the path.
|
||
|
// If path is /*, matches all subpaths including /
|
||
|
$keypath = empty($keyurl->path)?"/":$keyurl->path;
|
||
|
$sitepath = empty($siteurl->path)?"/":$siteurl->path;
|
||
|
|
||
|
// Trim trailing / from both paths before comparison
|
||
|
if (\strlen($sitepath) > 1) {
|
||
|
$sitepath = \rtrim($sitepath,"/");
|
||
|
}
|
||
|
if (\strlen($keypath) > 1) {
|
||
|
$keypath = \rtrim($keypath,"/");
|
||
|
}
|
||
|
|
||
|
// Do a case insensitive fnmatch on the site so wildcards are matched too.
|
||
|
return \fnmatch($keypath,$sitepath,\FNM_CASEFOLD);
|
||
|
}
|
||
|
|
||
|
$tests = [
|
||
|
["*", "https://www.miqra.nl"],
|
||
|
["*/*", "https://www.miqra.nl"],
|
||
|
["*", "https://clients.openedu.nl/fith"],
|
||
|
["clients.openedu.nl/fith", "https://clients.openedu.nl/fith/"],
|
||
|
["clients.openedu.nl/fith/", "https://clients.openedu.nl/fith"]
|
||
|
];
|
||
|
|
||
|
foreach($tests as $test) {
|
||
|
[$key, $site] = $test;
|
||
|
print("Checking key '{$key}' on site '{$site}': " . (sitematch($key,$site)?"MATCH":"FAIL") . "\n");
|
||
|
}
|