質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • PHP

    20775questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

ホスト名からドメインだけを取り出したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,187

flat

score 591

ホスト名からドメインの部分だけを取り出したいと思い、まだ途中ですが次のようなコードを書きました。
しかし、ドメインがTLDだけなら話は簡単なのですが、SLDも想定しなければいけないため頭を悩ませています。
とりあえず余計な部分を削ぎ落とすところまでは考えたのですが、ここからSLDが無い場合でもドメインのみの状態にするにはどのような処理が必要でしょうか?

追記
この処理で私が今回行おうとしている事は、サーバーにアクセスしてきたホストのドメインを取得する(だけ)というものです。(正引きで確認済み)
つまりプロバイダなどの通信事業者を経由したアクセスを想定しているので、よく考えると地域型ドメインは考慮しなくても良いです。(多分……)

$hostname1 = 'www.example.com'; // example.com
$hostname2 = 'www.example.co.jp'; // example.co.jp
$hostname3 = 'xxx.yyy.www.example.tokyo.jp'; // example.tokyo.jp
$hostname4 = 'www.example.shibuya.tokyo.jp'; // example.shibuya.tokyo.jp

$arr = array_reverse(explode('.', $hostname4), TRUE);

// 地域型ドメインだと4レベルドメインになる事を考慮
if (count($arr) > 4) {// 3 だったのを 4に変更
  array_splice($arr, 4);// 3 だったのを 4に変更
}

// さてここからどうしよう……という状態です。

追記2
ngyukiさんの回答にあるコードを参考に試行錯誤していたのですが、色々と妥協していった結果、今回は省コストであることを優先することにしました。
コードは最終的に次のようになりました。

$hostname1 = 'teratail.com';                 // teratail.com
$hostname2 = 'www.example.com';              // example.com
$hostname3 = 'www.example.jp';               // example.jp
$hostname4 = 'www.example.co.jp';            // example.co.jp
$hostname5 = 'xxx.yyy.www.example.ne.jp';    // example.ne.jp
$hostname6 = 'xxx.yyy.www.example.tokyo.jp'; // tokyo.jp
$hostname7 = 'tokyo.jp';                     // tokyo.jp
$hostname8 = 'oreore.areare';                // oreore.areare

/**
 * @param string $hostname ホスト名
 * @return string 一般的なドメインであればドメイン名を、そうでない場合はunknownを返す
 */
function narrow_down_domain($hostname) {
  if ($hostname === 'unknown') {
    return $hostname;
  }

  $arr = array_reverse(explode('.', $hostname));

  if (strlen($arr[1]) > 2) {
    $domain = implode('.', array_reverse(array_slice($arr, 0, 2)));
  } elseif (strlen($arr[1]) < 3) {
    $domain = implode('.', array_reverse(array_slice($arr, 0, 3)));
  } else {
    $domain = 'unknown';
  }

  return $domain;
}

/**
 * 都道府県型JPドメインおよび地域型ドメイン(またはそれに類するドメイン)は諦める
 * つまり、正確に取得することは諦める
 * $hostname8 のようなケースは、ホスト名を取得する段階の処理で、信頼できないホスト名だった場合は'unknown'を返すようにする事で対処する
 */
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+7

この問題、一意な解法はありません。
都道府県ドメインと地域ドメインのリストを全部自分で持つくらいしか(日本の都道府県・地域ドメインを自分で持ったとして、各国の似たような制度はどうしたものですかね)。

ホスト名のうちどこまでがドメイン名かわからないという問題はCookieの安全性問題にもなっていて、Cookie Monsterと呼ばれています。
http://blog.tokumaru.org/2011/09/jpcookie.html

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/29 23:08

    回答して下さりありがとうございます。
    リンク先を拝見しましたが、地域型ドメインだと4レベルのドメインになるんですね……。
    頭が痛いです。
    また、仰るように地域型ドメインと都道府県型ドメインを網羅出来たとしても、外国まで考えるとなると相当骨が折れそうですし、増える度に対応しなければいけないので大変ですね。
    国外のものは諦めて例外処理にでも回すのが無難そうかなと思いました……。
    完全な解決は諦めて、自分なりに試行錯誤してみます。

    キャンセル

+4

このコードは半分ネタみたいなもので、正確かどうかもわかりませんが・・・

public_suffix_list というものがあるので、これを利用して、

<?php
$cache = '/tmp/public_suffix_list.dat';

if (file_exists($cache) === false) {
    file_put_contents(
        $cache,
        file_get_contents('https://publicsuffix.org/list/public_suffix_list.dat')
    );
}

$list = file($cache);

$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
$list = array_filter($list, function ($v) {
    return substr($v, 0, 2) != '//';
});

$list = array_flip($list);

$hosts = [
    'www.example.com',
    'www.example.co.jp',
    'xxx.yyy.www.example.tokyo.jp',
    'www.example.shibuya.tokyo.jp',
    'teratail.com',
    'tokyo.jp',
    'oreore.areare',
];

function detectDoamin($host)
{
    global $list;

    $arr = explode('.', $host);

    for ($i=0; $i<count($arr); $i++) {
        $suffix = implode('.', array_slice($arr, $i));

        if (isset($list[$suffix]) === false) {
            continue;
        }

        if ($i > 0) {
            $domain = implode('.', array_slice($arr, max($i-1, 0)));
        } else {
            $domain = $host;
        }

        return $domain;
    }

    return false;
}

foreach ($hosts as $host) {
    $domain = detectDoamin($host);

    if ($domain === false) {
        echo "$host => unknown!!!\n";
    } else {
        echo "$host => $domain\n";
    }
}

次のような結果になります。

www.example.com => example.com
www.example.co.jp => example.co.jp
xxx.yyy.www.example.tokyo.jp => example.tokyo.jp
www.example.shibuya.tokyo.jp => example.shibuya.tokyo.jp
teratail.com => teratail.com
tokyo.jp => tokyo.jp
oreore.areare => unknown!!!

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/30 00:28 編集

    回答して下さりありがとうございます。
    public_suffix_list!こんなリストがあるんですね。
    私も回答にあるコードを試してみましたが、結果を見る限りではバッチリなように見えます。
    まだどの辺りの処理が肝なのかはちょっと分かりませんが、処理を追いながら理解してみようと思います。
    そしてやはりというか、リストをそのまま利用するとメモリを結構食いますね……。

    キャンセル

関連した質問

  • 解決済

    PHPを用いた記号の入力制限

    PHPで入力された記号を受け取り、キーコードに変換するコードを作成しています。 変換後にjsで実際の入力制限をかけるのですが、どうにも冗長なコードになってしまっています。 何か

  • 解決済

    URLを検知して配列に格納したい

    お世話になっております。 URLとタイトルがカンマ区切りで含まれている配列を読み込み、ドメインが格納されている配列を検知させたいのですが、 エラー文が表示されてしまいうまく

  • 解決済

    一番初めに検知された値のみ格納させたい

    お世話になります。 //ドメイン $domainList = array("sample.jp","sample.co.jp",sample.com"); //URL s

  • 解決済

    多次元配列の組み替え(基礎的な質問ですみませんが)

    以下のような多次元配列になっている場合に、単純な連想配列に変換することは可能でしょうか。 一方で、このような多次元配列に対してforeachでループ処理させることは可能なんでしょ

  • 解決済

    マルチサイト常時httpsについて

    表記の件につき、質問いたします。 /var/www/html/wordpressディレクトリ内にWordPressのプログラムファイルが全て入っています。 Wordpres

  • 解決済

    3つ以上の配列の多次元連想配列化+一部の配列について飛び石で取得

    現在以下の4つの配列があり、これを下部の多次元連想配列に組み替えたいと考えております。 <Before> ・元の配列 配列$tom array(3) { [0]=> str

  • 解決済

    PHPでの文字列操作についての質問です。

    PHP初心者です。 PHPを使って、ファイルからデータを読み込み、文字列を分割しようとしています。 読み込むファイルに 3 6 10 1 9 7 というデータ

  • 解決済

    phpでの配列結合

    前提・実現したいこと phpとMySQLを使ってガチャを制作しています。 その時にガチャの結果として帰ってくるIDの配列とIDを元に取得したカード配列から最終的に画面出力するカ

同じタグがついた質問を見る

  • PHP

    20775questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。