【メモ】とある連載を見ながらLaravelのルーティングの仕組み【.htaccess】

web系のサーバーサイドエンジニアを目指す奴のメモ書きです。
環境：Windows10

この連載の

https://codezine.jp/article/corner/765

第二回目の記事に沿ってやっていくよ！情報量多かったので分割します。

https://codezine.jp/article/detail/11370

前回はこれ！

https://qiita.com/4U5zo/items/080f9f7c90c99a1c9b73

前回、XAMPPのhtdocs配下にLaravelプロジェクトを作成した。そして`http://localhost/firstlaravel/public/hello`にアクセスするとHello World!が表示されるようにLaravelプロジェクト配下のroutesフォルダにあるweb.phpというファイルを以下のように変更した。
```php
<?php

use Illuminate\Support\Facades\Route;

//コメント省略

Route::get('/', function () {
    return view('welcome');
});

//追加
Route::get("/hello", function () {
	print("<h1>Hello World!</h1>");
	return null;
});
```

今回はなぜweb.phpを変更しただけでHello World!が出せたのかをルーティングの観点で学んでみるよ！

# 全てのリクエストはpublic/index.phpに通ず
前回Laravelプロジェクト配下のpublicフォルダについて少し学んだ。publicフォルダはLaravelプロジェクトで内で唯一外部に公開されている。つまりすべてのリクエストは唯一公開されているpublicフォルダにアクセスせざるを得ないということになる。前回アクセスしたURLを見ても`http://localhost/firstlaravel/public/`と`http://localhost/firstlaravel/public/hello`でどちらもちゃんとpublicフォルダにアクセスしていることが分かる。

実際のpublicフォルダを下記に示す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2626978/b7dfd224-f5fc-2411-8e82-3ebdf4985676.png)


勘のいい人は気が付いたかもしれないが`http://localhost/firstlaravel/public/hello`でアクセスしているがhelloなんてファイルはないし、ましてや`http://localhost/firstlaravel/public/`に関してはファイルの指定すらされていないということに。。。安心してください、

`http://localhost/firstlaravel/public/`や`http://localhost/firstlaravel/public/hello`のようにpublicフォルダに該当するファイルが存在しない場合、いったん`index.php`が実行されるようになっているんです！

ルーティングで困ったらとりあえず`index.php`に振ってしまえっていう作戦ですね。
ちなみに`index.php`に割り振るという作戦は同じくpublicフォルダにある`.htaccess`というファイルで設定しています。
次はこの`.htaccess`という参謀についてみていきましょう。

※基本的にセキュリティの観点でpublic配下には作成したソースは配置せず、すべてindex.phpに振るのがよいとされているようです。(index.phpしか置いてない=どのリクエストも存在しないファイルだからindex.phpが実行される。)
>勘違いしてる初心者は多いのですが、phpを動作させるためには別に必ずブラウザからアクセスできるところに.phpファイルを置かなきゃいけないというルールはありません。
コマンドからも実行できるので、Webサーバー内であればどこでも良いのです。
ブラウザから直接アクセス可能だと意図せず実行されてしまいますよね。
特にフレームワークではコアソース部分はそういった意図しない実行を防ぐためにドキュメントルート配下にはindex.phpしか置かない仕組みになっています。
https://teratail.com/questions/223840

# .htaccessという参謀
`.htaccess`はフォルダ単位でApacheの設定をできるファイルらしいです。
中身を確認すると以下のようになっています。
```
<IfModule mod_rewrite.c>

    # 省略

    RewriteEngine On

    # 省略

    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>
```
処理の内容をざっくり説明すると、ApacheのURL書き換えモジュールが使えるなら、それを使用。一致するファイル名、フォルダ名がない場合はURLをindex.phpに書き換えるという処理をしています。

では順番に解読していきましょう！

## `<IfModule mod_rewrite.c>`とは
`mod_rewrite.c`とはURLの書き換え・リダイレクト処理を行うApacheのモジュールです。
`<IfModule モジュール名>`でモジュールが利用できる状態か確認して、利用できるときのみタグ内の処理を実施します。つまりmod_rewrite.cが利用可能であればタグ内の処理を実施します。

## RewriteEngine Onとは
`RewriteEngine On`でmod_rewriteの機能を有効化することができます。
これはシンプルに`RewriteEngine Off`でmod_rewriteの機能を無効化できます。

## RewriteCond %{REQUEST_FILENAME} !-d　と　RewriteCond %{REQUEST_FILENAME} !-fとは
`RewriteCond`はURLの書き換えを行う条件を設定します。
今回の例のように2つの条件ががただ続いている場合はAND条件を表しています。
```
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
```
OR条件を表したい場合は[OR]をくっつけてあげる必要があります。
```
    RewriteCond %{REQUEST_FILENAME} !-d [OR]
    RewriteCond %{REQUEST_FILENAME} !-f
```
今回はAND条件なので`%{REQUEST_FILENAME} !-d`と`%{REQUEST_FILENAME} !-f`両方を満たす場合にURLが書き換えられます。

`%{REQUEST_FILENAME}`はHTTP環境変数のREQUEST_FILENAMEを参照しています。
HTTP環境変数については下記のように説明されています。
>リクエストを受け取った側がCGIやPHPなどのプログラムの場合，HTTPリクエストヘッダの情報や、アクセス元のIPアドレス，TCPポート番号などの情報を環境変数に設定します。 環境変数にはクライアント側の情報だけでなく，サーバ側の情報も含まれます。
https://www.blackstone.jp/tech/memo/env.php

つまりリクエストの際にありとあらゆる情報を環境変数に設定して情報として活用できる状態にしているということです！
その中にREQUEST_FILENAMEという環境変数があり、リクエストされたサーバーパス情報を持っています。

残るのは`!-d`と`!-f`だけです！
`-d`はディレクトリであればTRUEです。`-f`はファイルであればTRUEです。
そこにそれぞれ否定の意味の`!`が付いているので条件が反転します。
`!-d`はディレクトリでなければTRUEで、`!-f`はファイルでなければTRUEです。

条件については少し長くなってしまいましたがまとめると、リクエストされたサーバのパスがディレクトリでもファイルでもなければTRUEということになります。
```
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
```

# RewriteRule ^ index.php [L]とは
RewriteRuleは記述した内容でリクエストURLの書き換えをします。
書き換えといっても単に読み込むファイルを変更するだけの場合と別のURLに差し替えて他のページを表示(リダイレクト)する場合の2パターンがあります。
今回見ている箇所は単に読み込むファイルを変更するだけの場合です。リダイレクトにはRewriteRuleの末尾に[R=301]のようなものが付いています。
今回でいうとリクエストURLが`http://localhost/firstlaravel/public/hello`ですが単に読み込むファイルを変更するだけの場合、ブラウザに表示されるURLは`http://localhost/firstlaravel/public/hello`のまま、表示ファイルのみ`D:\XAMPP\XAMPP\htdocs\firstlaravel\public\index.php`に変更します。

最初は.htaccessのRewriteRuleの書き換えの処理内容が調べてもさっぱりわからなかったためteratailで教えていただきました。回答してくださった方ありがとうございました！

https://teratail.com/questions/n6ru4bxtms8un1

RewriteRuleの変換処理についてここに記載すると長くなってしまうため、また記事を作成したらこちらにリンクを掲載いたします。
この場では一旦RewriteRuleではリクエストURLを別のファイルへのアクセスに変換するということをやっているということだけにとどめておきます。

[L]はURL書き換えを終了します。(LastのL)
ただ注意しないといけない点として[L]を点ければそこで処理が終了するわけではないということです。
[L]は確かに最後ですが、[L]に到達したらもう一度先頭に戻って書き換え後のURLで再度条件に一致するか確認します。最終的にどの条件にも一致しなくなって初めて処理を抜けます。



# .htaccessの学習課題
・.htaccessは推奨されておらず、できるだけhttpd.confで設定する方がよいらしいのでRewriteRuleの記述をhttpd.confでできるようにする。

参考資料
https://codezine.jp/article/detail/11370
https://html-coding.co.jp/knowhow/tips/wp_modrewrite/
https://pasomaki.com/htaccess-environment-variable/
https://itlog.unknown-r.com/5
https://laraweb.net/environment/9367/
https://ysklog.net/mod-rewrite/rewrite-base.html
https://www.suzu6.net/posts/239-laravel-htaccess/
https://www.javadrive.jp/apache/htaccess/index4.html#section1