URLの正規化とDirectoryIndexのお話

URLの末尾が/index.html /index.php /といった形で重複コンテンツ・重複URLが発生してしまった時、よく「/」で止める形で正規化をしますよね。
では、同じディレクトリに「index.html」と「index.php」が共存していた場合、「/」で止めた時にどちらが表示されるかご存知でしょうか?

「そもそも両方が存在することなんてあるの?」と思うかもしれません。

同じディレクトリに「index.html」と「index.php」が共存している場合でも、/about/index.html /about/index.phpのように、URLにファイル名を含めることで、それぞれのファイルを表示させることができますし、何も間違ってはいません。Perlが主流だったころは「index.cgi」と「index.html」が同居していることがよくありました。構築の手法も変わり、一般的なサイトやシステムではあまり見かけなくなりましたが、それでも近年数回は見たことがあるので、無くはないのです。

さて最初の質問に戻って、答えは次のどれでしょうか?

  • A:「index.php」でしょ。
  • B:「index.html」でしょ。
  • C:サーバによるでしょ。

正解は「C:サーバによる」です。

つまり正規化をしようとしているサーバの設定を確認せずに実行した場合、予期せぬ問題が発生する可能性があるということですね。 「具体的に何がおきるの?」が分かりにくいと思うので、例を挙げて解説したいと思います。(ちなみにフィクションですw)

きれいに落とし穴に落ちる正規化の例

次の図左のようなディレクトリ・ファイル構造のサイトがあったとします。
「/company」「/recruit」「/sitemap」 配下にはそれぞれ、「index.html」もしくは「index.php」が置かれている状態ですが、リンクURLが/止めだったり/index.htmlだったりと統一されていなかったこともあり、同じコンテンツで複数のURLが発生し、それらが検索エンジンにインデックスされている状態でした。

重複コンテンツ・重複URLが発生している例

これはいけない、正規化しないと!
焦った担当者は技術者に正規化を依頼しました。

/index.html/index.phpのURLが重複しているから/に正規化してほしい!

この依頼に対し、技術者は次の正規化処理を.htaccessに追記しました。

RewriteCond %{THE_REQUEST} ^.*/index.(html|php)
RewriteRule ^(.*)index.(html|php)$ $1 [R=301,L]

サイトのグランドトップを始め、ディレクトリ直下の/index.html,/index.phpへのリクエストを/に書き直す指定になっています。

良かった!URLは次のように正規化されました。ステキ!

正規化された例

落とし穴発覚

間もなく不具合が見つかりました。
「about」の動的URLのコンテンツが表示されなくなってしまったのです。

不具合が発覚した例

何が起きたのでしょうか?ヒントは冒頭にあったアレです。

サーバの設定で優先される拡張子が決まる

この例の場合、正規化されてURLが/止まりになると「index.html」か「index.php」どちらかが表示されます。このどちらが優先されるかは、Webサーバ(Apache)の設定「DirectoryIndex」の値によって決まります。それぞれの設定を再現したデモページを用意したので、「index.php」が優先の場合・「index.html」が優先の場合の挙動を見てみてください。

index.phpが優先される設定の場合

index.phpが優先される場合の動作確認

この設定では、動的URLは正しく処理されますが、/about/で表示する予定だった/about/index.htmlは表示されなくなります。

index.htmlが優先される設定の場合

index.htmlが優先される場合の動作確認

/about/index.phpが使われる機会はなくなり、パラメータ付きのURLは残るものの、動的処理が実行されることはなくなります。

つまり、上の例ではサーバの設定で「index.html」が優先される設定だった、ということです。

DirectoryIndexについて

DirectoryIndexは、Apacheのconfigファイルであるhttpd.conf内で設定されています。VPSなどWebサーバの構築や設定をする人以外、直接編集することはないファイルです。

次のような設定ブロックで、DirectoryIndexに続いて指定されたファイルが左から順に優先的に処理されていきます。下の例だと、「index.htm」が存在すれば「index.html」より優先して採用されることになります。「index.php」と「index.html」がある場合、「index.php」が採用されるわけです。

# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#
<IfModule dir_module>
    DirectoryIndex index.php index.cgi index.shtml index.htm index.html
</IfModule>

DirectoryIndexは.htaccessでも指定できます

デフォルトで設定された優先順位が要件に合わない場合、.htaccessで任意の順番に設定を変更することができます。(一部レンタルサーバでは設定変更が許可されていない場合もあります)
記述はhttpd.confと同様に、次のように指定します。

DirectoryIndex index.html index.php

まとめ

運用されているサイトに対して正規化の作業依頼が発生する場合、発起人はSEOやアクセス解析を見ているマーケターやアナリスト、Webマスターであることが多いと思います。ファイル構造が実際どうなっているかはFTPでサーバ内を見てみないと分からないこともあり、index.htmlとindex.phpが同じディレクトリに同居していることに気が付かず、実施にGOが掛かってしまうこともあるかもしれません。

でも、正規化を始めURLを設定する・変えるという作業は、表面上だけでなく裏側(サーバ)にもガッツリ関係しています。トラブルを未然に防ぐために、「着手前にサーバの設定内容やファイル構造をきちんと調べる時間と費用が必要だ」という主張が、制作を請け負う側にももう少し必要なのかなと思ったりします。