gavu
gavu

Reputation: 49

PHP sort list of subdomains by domain

I have a list of domains (array)

sub1.dom1.tld1
sub2.dom2.tld2
sub1.sub2.dom1.tld1
sub3.dom1.tld3

I want to achieve the following:

dom1.tld1
-> sub1.dom1.tld1
-> sub2.dom1.tld1
--> sub1.sub2.dom1.tld1

dom2.tld2
-> sub2.dom2.tld2

dom1.tld3
-> sub3.dom1.tld3

I have tried to adapt this, but it doesn't really fit:

How to alphabetically sort a php array after a certain character in a string

I would appreciate any kind of help.

Upvotes: 1

Views: 277

Answers (4)

Balalen
Balalen

Reputation: 498

i'm not sure if this is a late answer, but here it how i achieved it

First i have function to get the host name from subdomain

function getHost($a)
{
    $tld = preg_replace('/.*\.([a-zA-Z]+)$/', '$1', $a);
    return trim(preg_replace('/.*(([\.\/][a-zA-Z]{2,}){' . ((substr_count($a, '.') <= 2 && mb_strlen($tld) != 2) ? '2,3' : '3,4') . '})/im', '$1', $a), './');
}

Next you need to loop through the subdomains and get their main domain and store it in array

$domains = [
    'sub.bbb.com',
    'www.aaa.com',
    '*.zzz.com',
    'aaa.com',
    '*.sub.bbb.com',
    'zzz.com',
    'beta.bbb.com',
    'bbb.com',
    'aaa.fr',
];


$allMainDomains = array();

foreach ($domains as $domainValue) {
    if (!in_array(getHost($domainValue), $allMainDomains)) {
        array_push($allMainDomains, getHost($domainValue));
    }
}

What we did is, we store all main domains in an array $allMainDomains and verified not duplicates by using in_array function

Next we can loop through the $allMainDomains and $domains like so

foreach ($allMainDomains as $mainDomain) {
    echo '<br>' . $mainDomain . '<br>';

    foreach ($domains as $subDomain) {
        if (getHost($subDomain) == $mainDomain) {
            echo '<br>' . $subDomain . '<br>';
        }
    }
    echo '<hr />';
}

Note: The only thing you might need to modify is the getHost function because it skips the multiple dots (.) domains

Result

Resul

Upvotes: 0

Soullivaneuh
Soullivaneuh

Reputation: 3863

Here is an approach similar to @Elementary answer combine to @CBO one:

$domains = [
    'sub.bbb.com',
    'www.aaa.com',
    '*.zzz.com',
    'aaa.com',
    '*.sub.bbb.com',
    'zzz.com',
    'beta.bbb.com',
    'bbb.com',
    'aaa.fr',
];


// @see https://stackoverflow.com/a/61461912/1731473
$computeDomainToSort = static function (string $domain): string {
    return \implode(
        '.',
        array_reverse(
            explode('.', $domain,
                // Keep the base domain.tld collapsed for comparison.
                substr_count($domain, '.')
            )
        )
    );
};

\usort($this->domains, static function (string $domain1, string $domain2) use ($computeDomainToSort): int {
    $domain1 = $computeDomainToSort($domain1);
    $domain2 = $computeDomainToSort($domain2);

    return strnatcmp($domain1, $domain2);
});

That way, given domains will be sorted like this:

aaa.com
www.aaa.com
aaa.fr
bbb.com
beta.bbb.com
sub.bbb.com
*.sub.bbb.com
zzz.com
*.zzz.com

The main difference is on the $computeDomainToSort lambda function, where I keep the base domain.tld onto one piece to have a more natural sorting.

Upvotes: 0

Elementary
Elementary

Reputation: 1453

You can proceed like this:

$array=array(
'sub1.dom1.tld1',
'sub2.dom2.tld2',
'sub1.sub2.dom1.tld1',
'sub2.sub2.dom1.tld1',
'sub3.sub2.dom1.tld1',
'sub3.dom1.tld3');

function cmp($a,$b){
    $a=array_reverse(explode('.',$a));
    $b=array_reverse(explode('.',$b));
    $ca=count($a);
    $cb=count($b);
    $string='';;
    for($i=0,$c=min($ca,$cb);$i<$c;$i++){
        $result=strnatcmp($a[$i],$b[$i]);
        if($result!==0) return $result;

    }
    return $result;
}

usort($array,'cmp');
print_r($array);

and the output is:

Array
(
    [0] => sub1.dom1.tld1
    [1] => sub1.sub2.dom1.tld1
    [2] => sub2.sub2.dom1.tld1
    [3] => sub3.sub2.dom1.tld1
    [4] => sub2.dom2.tld2
    [5] => sub3.dom1.tld3
)

Upvotes: 0

Sean M
Sean M

Reputation: 181

I've had to attack a similar headache before. In the short term I flip the order of the domain components and use a hidden sorting column in a table/view: $sortstring = implode('.',array_reverse(explode('.', $domain)));

In the long term I saved the reverse format of the domain records before saving changes to the DB into a computed field/column so that it didn't have to be re-computed every time the domain list is viewed.

If you don't want that sub-domain, just remove the last element of the array after the flip....

Upvotes: 1

Related Questions