【问题标题】:Delete subdomain from url string if subdomain is found如果找到子域,则从 url 字符串中删除子域
【发布时间】:2014-02-16 09:41:31
【问题描述】:

我有一个这样的域数组:

domain.com
second.com
www.third.com
www.fourth.fifth.com
sixth.com
seventh.eigth.com

我想要的是一个只返回主机的函数。没有子域。

这段代码是我目前获取主机名的代码:

$parse = parse_url($url);
$domain = $parse['host'];

但这只会返回这个:

domain.com
second.com
third.com
fourth.fifth.com
sixth.com
seventh.eigth.com

我需要这个输出:

domain.com
second.com
third.com
fifth.com
sixth.com
eigth.com

【问题讨论】:

  • www.amazon.co.uk 呢?按照你的规则,应该是co.uk,这显然是错误的。
  • This list of public suffixes 可能对你们中的一些人感兴趣

标签: php url-rewriting


【解决方案1】:
function giveHost($host_with_subdomain) {
    $array = explode(".", $host_with_subdomain);

    return (array_key_exists(count($array) - 2, $array) ? $array[count($array) - 2] : "").".".$array[count($array) - 1];
}

【讨论】:

  • 这很好用。谢谢巴蒂斯特!我只是不知道为什么。你能评论一下代码吗?尤其是“回声……”这一行……​​
  • 正如 Marc B 上面指出的,这将为“amazon.co.uk”返回“co.uk”。如果您知道您的子域将始终具有单部分顶级域名,那么您很好,否则您将必须创建可能的多部分顶级域名列表,并确保您没有剥离您不应该剥离的东西。跨度>
【解决方案2】:

试试这个代码

 <?php
    /**
    * @param string $domain Pass $_SERVER['SERVER_NAME'] here
    * @param bool $debug
    *
    * @debug bool $debug
    * @return string
    */
    function get_domain($domain, $debug = false) {
        $original = $domain = strtolower($domain);     
        if (filter_var($domain, FILTER_VALIDATE_IP)) { return $domain; }    

        $debug ? print('<strong style="color:green">&raquo;</strong> Parsing: '.$original) : false; //DEBUG 

        $arr = array_slice(array_filter(explode('.', $domain, 4), function($value){
                            return $value !== 'www'; }), 0); //rebuild array indexes

        if (count($arr) > 2)    {
            $count = count($arr);
            $_sub = explode('.', $count === 4 ? $arr[3] : $arr[2]);

            $debug ? print(" (parts count: {$count})") : false; //DEBUG

            if (count($_sub) === 2)  { // two level TLD
                $removed = array_shift($arr);
                if ($count === 4) // got a subdomain acting as a domain
                    $removed = array_shift($arr);            
                $debug ? print("<br>\n" . '[*] Two level TLD: <strong>' . join('.', $_sub) . '</strong> ') : false; //DEBUG
            }
            elseif (count($_sub) === 1){ // one level TLD
                $removed = array_shift($arr); //remove the subdomain             
                if (strlen($_sub[0]) === 2 && $count === 3) // TLD domain must be 2 letters
                    array_unshift($arr, $removed);                
                else{
                    // non country TLD according to IANA
                    $tlds = array(    'aero',    'arpa',    'asia',    'biz',    'cat',    'com',    'coop',    'edu',    'gov',    'info',    'jobs',    'mil',    'mobi',    'museum',    'name',    'net',    'org',    'post',    'pro',    'tel',    'travel',    'xxx',    );             
                    if (count($arr) > 2 && in_array($_sub[0], $tlds) !== false) {//special TLD don't have a country
                        array_shift($arr);
                    }
                }
                $debug ? print("<br>\n" .'[*] One level TLD: <strong>'.join('.', $_sub).'</strong> ') : false; //DEBUG
            }
            else { // more than 3 levels, something is wrong
                for ($i = count($_sub); $i > 1; $i--) 
                    $removed = array_shift($arr);

                $debug ? print("<br>\n" . '[*] Three level TLD: <strong>' . join('.', $_sub) . '</strong> ') : false; //DEBUG
            }
        }
        elseif (count($arr) === 2) {
            $arr0 = array_shift($arr);     
            if (strpos(join('.', $arr), '.') === false
                        && in_array($arr[0], array('localhost','test','invalid')) === false) // not a reserved domain
            {
                $debug ? print("<br>\n" .'Seems invalid domain: <strong>'.join('.', $arr).'</strong> re-adding: <strong>'.$arr0.'</strong> ') : false; //DEBUG
                // seems invalid domain, restore it
                array_unshift($arr, $arr0);
            }
        }     

        $debug ? print("<br>\n".'<strong style="color:gray">&laquo;</strong> Done parsing: <span style="color:red">' . $original . '</span> as <span style="color:blue">'. join('.', $arr) ."</span><br>\n") : false; //DEBUG     
        return join('.', $arr);
    }


     //TEST
    $urls = array(
    'www.example.com' => 'example.com',
    'example.com' => 'example.com',
    'example.com.br' => 'example.com.br',
    'www.example.com.br' => 'example.com.br',
    'www.example.gov.br' => 'example.gov.br',
    'localhost' => 'localhost',
    'www.localhost' => 'localhost',
    'subdomain.localhost' => 'localhost',
    'www.subdomain.example.com' => 'example.com',
    'subdomain.example.com' => 'example.com',
    'subdomain.example.com.br' => 'example.com.br',
    'www.subdomain.example.com.br' => 'example.com.br',
    'www.subdomain.example.biz.br' => 'example.biz.br',
    'subdomain.example.biz.br' => 'example.biz.br',
    'subdomain.example.net' => 'example.net',
    'www.subdomain.example.net' => 'example.net',
    'www.subdomain.example.co.kr' => 'example.co.kr',
    'subdomain.example.co.kr' => 'example.co.kr',
    'example.co.kr' => 'example.co.kr',
    'example.jobs' => 'example.jobs',
    'www.example.jobs' => 'example.jobs',
    'subdomain.example.jobs' => 'example.jobs',
    'insane.subdomain.example.jobs' => 'example.jobs',
    'insane.subdomain.example.com.br' => 'example.com.br',
    'www.doubleinsane.subdomain.example.com.br' => 'example.com.br',
    'www.subdomain.example.jobs' => 'example.jobs',
    'test' => 'test',
    'www.test' => 'test',
    'subdomain.test' => 'test',
    'www.detran.sp.gov.br' => 'sp.gov.br',
    'www.mp.sp.gov.br' => 'sp.gov.br',
    'ny.library.museum' => 'library.museum',
    'www.ny.library.museum' => 'library.museum',
    'ny.ny.library.museum' => 'library.museum',
    'www.library.museum' => 'library.museum',
    'info.abril.com.br' => 'abril.com.br',
    '127.0.0.1' => '127.0.0.1',
    '::1' => '::1',
    );

    $failed = 0;
    $total = count($urls);

    foreach ($urls as $from => $expected){
        $from = get_domain($from, true);
        if ($from !== $expected){
            $failed++;
            print("<div style='color:fuchsia;'>expected {$from} to be {$expected}</div>");
        }
    }    
    if ($failed)    
        print("{$failed} tests failed out of {$total}");    
    else    
        print("Success");   

所有功劳归pocesar

【讨论】:

  • 感谢 shanoop,对我不起作用,因为我检查了数百万个网址...所以这个版本会浪费我很多脚本时间...
  • @DoJoChi 如果您非常确定您的百万网址的可能性。然后你可以选择 Baptiste Donaux 的那一款。该代码将在具有国家 TLD 的域上失败。如果您删除所有这些测试和调试行,则此函数为 46 行。
【解决方案3】:

我更喜欢使用正则表达式来执行此操作,这对我来说更容易理解:

$url = "http://www.domain.com";
$parse = parse_url($url);
echo preg_replace("/^([a-zA-Z0-9].*\.)?([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z.]{2,})$/", '$2', $parse['host']); 

【讨论】:

  • 正则表达式非常棒,而且是 unitool!感谢分享!这应该是接受答案,没有功能或从 github 拉文件! [a-zA-Z0-9][a-zA-Z0-9-]+ 不会比 [a-zA-Z0-9][a-zA-Z0-9-]{1,61} 更优雅吗?
  • 这是迄今为止最简单的方法。但是有一个小错误。例如,您的答案正确地解析了结尾带有 .co.uk 的网址,但有些结尾带有 .com.au 之类的网址,并且在这种情况下,此正则表达式无法正确解析它。
  • 向这个致敬,绝对是最高效的。
【解决方案4】:

这是适用于所有域的一个,包括具有二级域(如“co.uk”)的域

function strip_subdomains($url){

    # credits to gavingmiller for maintaining this list
    $second_level_domains = file_get_contents("https://raw.githubusercontent.com/gavingmiller/second-level-domains/master/SLDs.csv");

    # presume sld first ...
    $possible_sld = implode('.', array_slice(explode('.', $url), -2));

    # and then verify it
    if (strpos($second_level_domains, $possible_sld)){
        return  implode('.', array_slice(explode('.', $url), -3));
    } else {
        return  implode('.', array_slice(explode('.', $url), -2));
    }
}

【讨论】:

    【解决方案5】:

    在需要检查“localhost”之前,我一直在使用 Baptiste Donaux 的版本。我认为Shanoop的版本更可靠。

    我已经在一个包含 190 个断言的测试套件中测试了这两个版本,并且对性能没有太大影响。如果仍然担心毫秒,您可以使用 Redis 或类似的东西在生产中缓存结果。

    这是 Shanoop 的答案的相同版本,但没有调试行并进行了一些清理:

    function stripSubdomain($domain) 
    {
        $domain = strtolower($domain);
        if (isIp($domain)) ? return $domain;
        return stripArray( buildArray($domain) );
    }
    
    function isIp($domain)
    {
        return (filter_var($domain, FILTER_VALIDATE_IP));
    }
    
    function buildArray($domain)
    {
        return array_slice(array_filter(explode('.', $domain, 4), function($value){
                                                                      return $value !== 'www';
                                                                  }), 0);
    }
    
    function stripArray($arr)
    {
        // TLD Domains
        if (count($arr) > 2) {
            $count = count($arr);
            $_sub = $this->retrieveSubdomain($arr);
    
            // two level TLD
            if (count($_sub) === 2)  {
                array_shift($arr);
                if ($count === 4) array_shift($arr);
            }
    
            // one level TLD
            elseif (count($_sub) === 1){
                $removed = array_shift($arr);
                if (strlen($_sub[0]) === 2 && $count === 3) array_unshift($arr, $removed);
    
                else {
                    // non country TLD according to IANA
                    $tlds = ['aero', 'arpa', 'asia', 'biz', 'cat', 'com', 'coop',
                             'edu', 'gov', 'info', 'jobs', 'mil', 'mobi', 'museum',
                             'name', 'net', 'org', 'post', 'pro', 'tel', 'travel', 'xxx'];
    
                    if (count($arr) > 2 &&
                        in_array($_sub[0], $tlds) !== false) array_shift($arr);
                }
    
            }
    
            // more than 3 levels, something is wrong
            else
                for ($i = count($_sub); $i > 1; $i--) array_shift($arr);
    
        }
    
        // Special Domains
        elseif (count($arr) === 2) {
            $removed = array_shift($arr);
            $reserved = ['localhost','test','invalid'];
            if (strpos(join('.', $arr), '.') === false && in_array($arr[0], $reserved) === false)
                array_unshift($arr, $removed); // seems invalid domain, restore it
        }
    
        return join('.', $arr);
    }
    
    function retrieveSubdomain($arr)
    {
        return explode('.', (count($arr) === 4 ? $arr[3] : $arr[2]) );
    }
    

    【讨论】:

    • 我实际上已经在一个类中实现了它。如果这样做,只将第一个方法设为公开(并使用 $this->method 调用其他方法)。此外,还可以进行一些改进,例如从类构造函数中获取域并调用 $domain = new Domain('url.here');然后 $domain->stripSubdomain();
    【解决方案6】:

    这个适用于大多数领域,如果我必须自己说的话,它很优雅!

    public static function StripSubdomain($Domain) {
    
        $domain_array = explode('.', $Domain);
        $domain_array = array_reverse($domain_array);
    
        return $domain_array[1] . '.' . $domain_array[0];
    }
    

    【讨论】:

    • 我使用区域文件,只需要 com/net =]
    【解决方案7】:

    试试这个。我喜欢它的简单性,它在大多数用例中都适用。

    $domains = [
        "domain.com",
        "second.com",
        "www.third.com",
        "www.fourth.fifth.com",
        "openhours.colyn.dev"
    ];
    
    $domains = array_map(function ($domain) {
        $parts = explode('.', $domain);
        return implode('.', array_slice($parts, count($parts)-2));
    }, $domains);
    
    /**
    [
        "domain.com",
        "second.com",
        "third.com",
        "fifth.com",
        "colyn.dev",
    ]
    */
    

    不是超级健壮,但对我来说,它工作正常。

    【讨论】:

    • 这种做法是超级错误的。例如,bbc.co.uk 将返回 co.uk
    【解决方案8】:

    试试 str_replace();

    $parse = parse_url($url);
    $domain = str_replace('www.','',$parse['host']);
    

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      • 2017-09-20
      • 2011-06-20
      • 2015-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多