web-dev-qa-db-ja.com

PHPでドメイン名を検証する方法は?

正規表現を使用しなくても可能ですか?

たとえば、文字列が有効なドメインであることを確認したい:

domain-name
abcd
example

有効なドメインです。これらはもちろん無効です:

domaia@name
ab$%cd

等々。したがって、基本的には英数字で始まり、より多くのalnum文字に加えてハイフンがある場合があります。そして、それもalnum文字で終わらなければなりません。

それが不可能な場合、これを行うための正規表現パターンを提案してもらえますか?

編集:

なぜこれが機能しないのですか? preg_matchを間違って使用していますか?

$domain = '@djkal';
$regexp = '/^[a-zA-Z0-9][a-zA-Z0-9\-\_]+[a-zA-Z0-9]$/';
if (false === preg_match($regexp, $domain)) {
    throw new Exception('Domain invalid');
}
31
Richard Knop
<?php
function is_valid_domain_name($domain_name)
{
    return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
            && preg_match("/^.{1,253}$/", $domain_name) //overall length check
            && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)   ); //length of each label
}
?>

テストケース:

is_valid_domain_name? [a]                       Y
is_valid_domain_name? [0]                       Y
is_valid_domain_name? [a.b]                     Y
is_valid_domain_name? [localhost]               Y
is_valid_domain_name? [google.com]              Y
is_valid_domain_name? [news.google.co.uk]       Y
is_valid_domain_name? [xn--fsqu00a.xn--0zwm56d] Y
is_valid_domain_name? [goo gle.com]             N
is_valid_domain_name? [google..com]             N
is_valid_domain_name? [google.com ]             N
is_valid_domain_name? [google-.com]             N
is_valid_domain_name? [.google.com]             N
is_valid_domain_name? [<script]                 N
is_valid_domain_name? [alert(]                  N
is_valid_domain_name? [.]                       N
is_valid_domain_name? [..]                      N
is_valid_domain_name? [ ]                       N
is_valid_domain_name? [-]                       N
is_valid_domain_name? []                        N
130
velcrow

これにより、ドメインに有効な形式があるかどうかだけでなく、アクティブであるか、IPアドレスが割り当てられているかどうかも確認できます。

$domain = "stackoverflow.com";

if(filter_var(gethostbyname($domain), FILTER_VALIDATE_IP))
{
    return TRUE;
}

この方法では、DNSエントリがアクティブである必要があるため、DNSに属さずにドメイン文字列を検証する必要がある場合は、上記のvelcrowで指定された正規表現方法を使用してください。

また、この関数は、FILTER_VALIDATE_URLを使用してURL文字列を検証することを意図していません。ドメイン文字列は有効なURLではないため、ドメインにはFILTER_VALIDATE_URLを使用しません。

57
RoboTamer

PHP 7

// Validate a domain name
var_dump(filter_var('mandrill._domainkey.mailchimp.com', FILTER_VALIDATE_DOMAIN));
# string(33) "mandrill._domainkey.mailchimp.com"

// Validate an hostname (here, the underscore is invalid)
var_dump(filter_var('mandrill._domainkey.mailchimp.com', FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME));
# bool(false)

ここには記載されていません:http://www.php.net/filter.filters.validateおよびこれに関するバグのリクエストは次の場所にあります:https://bugs.php.net/bug.php?id=72013

11
Rob

まず、次の意味があるかどうかを明確にする必要があります。

  1. 個々のドメイン名ラベル
  2. ドメイン名全体(つまり、ドットで区切られた複数のラベル)
  3. ホスト名

区別が必要な理由は、NUL、@、および '.'文字を含む技術的にany文字をラベルに含めることができるためです。 DNSは8ビットに対応しており、「an\0odd\.l@bel」というエントリを含むゾーンファイルを持つことは完全に可能です。もちろん、ラベルを区切るラベルとラベル内のドットを区別するのが難しいため、これはお勧めできませんが、は有効です

ただし、URLにはHost名が必要であり、それらはRFC 952および1123によって管理されます。有効Host名はdomain名のサブセットです。具体的には、文字、数字、ハイフンのみが許可されます。さらに、最初と最後の文字をハイフンにすることはできません。 RFC 952は最初の文字に数字を許可しませんでしたが、RFC 1123はその後それを緩和しました。

したがって:

  • a-有効
  • 0-有効
  • a--無効
  • a-b-有効
  • xn--dasdkhfsd-有効(IDNのプニコードエンコーディング)

私の頭上では、単一の単純な正規表現でa-の例を無効にすることは不可能だと思います。 singleHostラベルを確認するために思いつく最高のものは:

if (preg_match('/^[a-z\d][a-z\d-]{0,62}$/i', $label) &&
   !preg_match('/-$/', $label))
{
    # label is legal within a hostname
}

さらに問題を複雑にするために、一部のドメイン名エントリ(通常はSRVレコード)は、アンダースコアで始まるラベルを使用します。 _sip._udp.example.com。これらはnotホスト名ですが、正当なドメイン名です。

9
Alnitak

usecheckdnsrrhttp://php.net/manual/en/function.checkdnsrr.php

$domain = "stackoverflow.com";

checkdnsrr($domain , "A");

//returns true if has a dns A record, false otherwise
9
jacktrade

たとえば、Erklanのアイデアを使用して、ドメイン名を分離したと思います。

 $ myUrl = "http://www.domain.com/link.php";
$myParsedURL = parse_url($ myUrl); 
 $ myDomainName = $ myParsedURL ['ホスト'];

あなたが使うことができます:

if(false === filter_var($ myDomainName、FILTER_VALIDATE_URL)){
 //テストに失敗しました
 
}

PHP5sフィルター関数は、私が考えていたまさにそのような目的のためです。

正規表現を使用していないため、厳密にあなたの質問に答えているわけではありません。

6
Cups

正規表現を使用しない別の方法を次に示します。

$myUrl = "http://www.domain.com/link.php";
$myParsedURL = parse_url($myUrl);
$myDomainName= $myParsedURL['Host'];
$ipAddress = gethostbyname($myDomainName);
if($ipAddress == $myDomainName)
{
   echo "There is no url";
}
else
{
   echo "url found";
}
4
Erkan BALABAN

正規表現は、ドメイン検証をチェックする最も効果的な方法です。正規表現(IMOは愚かです)を使用しないことに固執している場合は、ドメインの各部分を分割できます。

  • www。 /サブドメイン
  • ドメイン名
  • 。拡張

次に、ある種のループで各文字をチェックして、有効なドメインと一致することを確認する必要があります。

先ほど言ったように、正規表現を使用する方がはるかに効果的です。

3
James Brooks

正規表現は問題ありませんが、_preg_match_権利を使用していません。ブール値ではなく、int(0または1)を返します。 if(!preg_match($regex, $string)) { ... }と書くだけです

2

特定のドメイン名またはIPアドレスが存在するかどうかを確認する場合は、checkdnsrrを使用することもできます
こちらがドキュメントです http://php.net/manual/en/function.checkdnsrr.php

1
verdy

正しい答えは、あなたはしないということです...あなたはユニットテストされたツールにあなたのために仕事をさせます:

// return '' if Host invalid --
private function setHostname($Host = '')
{
    $ret = (!empty($Host)) ? $Host : '';
    if(filter_var('http://'.$ret.'/', FILTER_VALIDATE_URL) === false) {
        $ret = '';
    }
    return $ret;
}

さらに読む: https://www.w3schools.com/php/filter_validate_url.asp

1
Mike Q

正規表現を使用したくない場合は、これを試すことができます:

$str = 'domain-name';

if (ctype_alnum(str_replace('-', '', $str)) && $str[0] != '-' && $str[strlen($str) - 1] != '-') {
    echo "Valid domain\n";
} else {
    echo "Invalid domain\n";
}

しかし、前述のとおり、正規表現はこれに最適なツールです。

1
Matteo Riva

有効なドメインとは、私が登録できるもの、または少なくとも登録できるように見えるものです。これが、「localhost」名からこれを分離したい理由です。

そして最後に、Regexの回避がより高速になる場合の主な質問に興味がありました。これが私の結果です。

<?php
function filter_hostname($name, $domain_only=false) {
    // entire hostname has a maximum of 253 ASCII characters
    if (!($len = strlen($name)) || $len > 253
    // .example.org and localhost- are not allowed
    || $name[0] == '.' || $name[0] == '-' || $name[ $len - 1 ] == '.' || $name[ $len - 1 ] == '-'
    // a.de is the shortest possible domain name and needs one dot
    || ($domain_only && ($len < 4 || strpos($name, '.') === false))
    // several combinations are not allowed
    || strpos($name, '..') !== false
    || strpos($name, '.-') !== false
    || strpos($name, '-.') !== false
    // only letters, numbers, dot and hypen are allowed
/*
    // a little bit slower
    || !ctype_alnum(str_replace(array('-', '.'), '', $name))
*/
    || preg_match('/[^a-z\d.-]/i', $name)
    ) {
        return false;
    }
    // each label may contain up to 63 characters
    $offset = 0;
    while (($pos = strpos($name, '.', $offset)) !== false) {
        if ($pos - $offset > 63) {
            return false;
        }
        $offset = $pos + 1;
    }
    return $name;
}
?>

velcrowの関数 および10000回の反復と比較したベンチマーク結果( complete results には多くのコードバリアントが含まれています。最速のものを見つけるのは興味深いことでした。):

filter_hostname($domain);// $domains: 0.43556308746338 $real_world: 0.33749794960022
is_valid_domain_name($domain);// $domains: 0.81832790374756 $real_world: 0.32248711585999

$real_worldは、より良い結果を得るために極端に長いドメイン名を含んでいませんでした。そして今、私はあなたの質問に答えることができます:ctype_alnum()を使用すれば、正規表現なしでそれを実現することは可能ですが、preg_match()が速かったので、私はそれを好むでしょう。

「local.Host」が有効なドメイン名であるという事実が気に入らない場合は、代わりに この関数 を使用して、パブリックtldリストに対して有効にします。多分誰かが両方を組み合わせる時間を見つけます。

1
mgutt

シェルコマンドを実行できる場合、ドメインが登録されているかどうかを判断する最良の方法は次のとおりです。

ドメイン名が登録されていない場合、この関数はfalseを返します。それ以外の場合、ドメイン名を返します。

function get_domain_name($domain) { 
    //Step 1 - Return false if any Shell sensitive chars or space/tab were found
    if(escapeshellcmd($domain)!=$domain || count(explode(".", $domain))<2 || preg_match("/[\s\t]/", $domain)) {
            return false;
    }

    //Step 2 - Get the root domain in-case of subdomain
    $domain = (count(explode(".", $domain))>2 ? strtolower(explode(".", $domain)[count(explode(".", $domain))-2].".".explode(".", $domain)[count(explode(".", $domain))-1]) : strtolower($domain));

    //Step 3 - Run Shell command 'Dig' to get SOA servers for the domain extension
    $ns = Shell_exec(escapeshellcmd("Dig +short SOA ".escapeshellarg(explode(".", $domain)[count(explode(".", $domain))-1]))); 

    //Step 4 - Return false if invalid extension (returns NULL), or take the first server address out of output
    if($ns===NULL) {
            return false;
    }
    $ns = (((preg_split('/\s+/', $ns)[0])[strlen(preg_split('/\s+/', $ns)[0])-1]==".") ? substr(preg_split('/\s+/', $ns)[0], 0, strlen(preg_split('/\s+/', $ns)[0])-1) : preg_split('/\s+/', $ns)[0]);

    //Step 5 - Run another Dig using the obtained address for our domain, and return false if returned NULL else return the domain name. This assumes an authoritative NS is assigned when a domain is registered, can be improved to filter more accurately.
    $ans = Shell_exec(escapeshellcmd("Dig +noall +authority ".escapeshellarg("@".$ns)." ".escapeshellarg($domain))); 
    return (($ans===NULL) ? false : ((strpos($ans, $ns)>-1) ? false : $domain));
}

長所

  1. どのドメインでも動作しますが、一部のドメインではphp dns関数が失敗する場合があります。 (私の.proドメインはphp dnsで失敗しました)
  2. DNS(Aなど)レコードのない新しいドメインで動作します
  3. Unicodeフレンドリー

短所

  1. シェル実行の使用、おそらく
0
Ajay Singh

これは古い質問であることは知っていますが、Google検索での最初の回答だったので、関連性があるようです。私は最近、この同じ問題を抱えていました。私の場合の解決策は、パブリックサフィックスリストを使用することでした。

https://publicsuffix.org/learn/

リストされている言語固有の推奨ライブラリはすべて、ドメイン形式だけでなくトップレベルのドメイン妥当性も簡単に検証できるはずです。

0
jeffers102
<?php

if(is_valid_domain('https://www.google.com')==1){
  echo 'Valid';
}else{
   echo 'InValid';
}

 function is_valid_domain($url){

    $validation = FALSE;
    /*Parse URL*/    
    $urlparts = parse_url(filter_var($url, FILTER_SANITIZE_URL));

    /*Check Host exist else path assign to Host*/    
    if(!isset($urlparts['Host'])){
        $urlparts['Host'] = $urlparts['path'];
    }

    if($urlparts['Host']!=''){
        /*Add scheme if not found*/        if (!isset($urlparts['scheme'])){
        $urlparts['scheme'] = 'http';
        }

        /*Validation*/        
    if(checkdnsrr($urlparts['Host'], 'A') && in_array($urlparts['scheme'],array('http','https')) && ip2long($urlparts['Host']) === FALSE){ 
        $urlparts['Host'] = preg_replace('/^www\./', '', $urlparts['Host']);
        $url = $urlparts['scheme'].'://'.$urlparts['Host']. "/";            

            if (filter_var($url, FILTER_VALIDATE_URL) !== false && @get_headers($url)) {
                $validation = TRUE;
            }
        }
    }

    return $validation;

}
?>
0