この記事では.htaccess
の設定内容を解説していきます。
Laravelの.htaccessについて
Laravelのプロジェクトにアクセスがあるとpublic/index.php
を経由してroute
に振り分けられます。
その時、URIが画像やCSSなどpubilicディレクトリに存在するファイルを指している時はそのファイルを返し、それ以外はroute
に設定したページが返るような制御が行われています。
この制御部分を設定しているのがpublic/.htaccess
です。
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
mod_rewrite
mod_rewrite
はPCRE正規表現パーサーに基づくルールベースの書き換えエンジンです。
アクセスしてきたURLやヘッダーを書き換えたり、リダイレクトしたりする機能です。
RewriteEngine On
はこの機能を有効にします。
あとで説明しますがRewriteCond
は条件を示し、それに合うものがRewriteRule
によって書き換えられます。
Apache Module mod_rewrite | httpd.apache.org
mod_negotiation
mod_negotiation
はURIと合うディレクトリ内のファイルを探して選択する機能です。
2つのオプションに-
が付いており、それらの機能をオフにしています。
- Multiviewsは、受け取ったURIのファイルがないときファイル拡張子を賢く探してくれるもの。
例えばURIに
/path/dir/foo
ときてfoo
が無かったら、foo.*
となるファイルを探します。 - IndexesはURLがディレクトリにマップするリクエストであって、 且つ
DirectoryIndex
で指定したファイルが ディレクトリ内に無ければ、ディレクトリ内の一覧を整形して返します。
public/bar/index.html
みたいなHTMLやphpファイルがあるときに/bar/
で返したいときは、DirectoryIndex index.html index.php
の設定で可能です。
移行中や静的なページがある案件だとたまに設定します。
RewriteCondとRewriteRule
細かく見ていく前にRewriteCond
とRewriteRule
について説明します。
RewriteCond
はif文の条件みたいなもので、RewriteCond <条件> [flags]
といった書き方です。
条件は正規表現で表します。
RewriteCond
を続けて書くとAND
になり、オプションに[OR]
が付くとOR
です。
RewriteRule
は文字列を置換します。
書き方はRewriteRule <検索文字列> <置換文字列> [flags]
です。
また、どちらも予約語があり%{REQUEST_URI}
, %{HTTP_USER_AGENT}
といったように使うことができます。
mod_rewrite - Apache HTTP Server Version 2.4
Handle Authorization Header
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
HTTPヘッダーのAuthorizationを環境変数に代入しています。
[E=foo:value]
とすると環境変数foo
に値value
を入れます。
E|envの例をみると、画像ファイルのリクエストかどうかログに残したい場合にこのように書きます。
RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1]
CustomLog "logs/access_log" combined env=!image
ただ、環境変数HTTP_AUTHORIZATION
にいれるとアプリケーション側で利用できるのでしょうか?
末尾に乗せるNginxの書き方では書いていないようですので謎。
分かり次第追記します。
Redirect Trailing Slashes If Not A Folder...
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
LaravelのDocumentootはpublic
に向けます。
ここでは、(1行目)URIがpublic
配下に実在するディレクトリを指しておらず、(2行目)URIの末尾にスラッシュがついていたら、(3行目)末尾のスラッシュを取ったURIへリダイレクトします。
オプション-d
はディレクトリかどうかで!
で反対を意味するためディレクトリじゃない場合となります。
RewriteRule
の%1
は、2行目のRewriteCond
のかっこの中の文字列を指しています。
[L,R=301]
はL
がLastを表しこれ以降のRiwrite処理を行わない、R
がRidirectでHTTPステータス301でリダイレクトするという意味になります。
まとめると、URIが/foo/bar/
でpublic/foo/bar/
ディレクトリがない場合は/foo/bar
にリダイレクトします。
Send Requests To Front Controller...
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
ここも先ほどと似ています。
!-d
はpublic
配下にURIのディレクトリがない、かつ、!-f
ファイルもない場合です。
その場合、public/index.php
を実行します。
おまけ:Nginxではどう書くのか?
Nginxでは.htaccess
のようにディレクトリごとに設定ファイルがあることを認めていません。
そのため.htaccess
は無く、LaravelのプロジェクトではDeployment #nginx | laravel.comにあるように設定をする必要があります。
## .htaccessのリダイレクト設定に似た箇所を抜粋
index index.html index.htm index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
Nginxの方が後に出ただけあってスッキリ書ける印象。
おわりに
まだ理解できていないこともありますが、結構Apacheの仕様を読み込めてきました。 Apacheについてはこんなのも書いているので良ければどうぞ。
参考
- RewriteCondのANDとORの優先順位 - Qiita
OR
の方がAND
より強い。条件を(A or B) and (C or D)
としたいときに参考になる。