経緯
Laravel6.0
・Laravelはルートを指定していない場合$_SERVER
から取得する。
・$_SERVER
の値はサーバーの設定により決まる。
PHP: $_SERVER - Manual
・サーバーの設定が複雑で期待する値が取得できなかった。
・リダイレクトやrouteメソッドで生成されるURLに影響がでて正しく遷移できない。
結論
UrlGeneratorにルートURLを設定することで、生成されるURLを固定できる
public function boot()
{
// ルートURLを設定
Illuminate\Support\Facades\URL::forceRootUrl(\config('app.url'));
// 必要に応じてsslを強制する
if (\config('app.env') !== 'local') {
Illuminate\Support\Facades\URL::forceScheme('https');
}
}
APP_URL=https://foo.com
ソースコード(ざっくり)
Illuminate/Routing/UrlGenerator.php
にforcedRoot
を指定することで生成されるURLを変更できる。
public function formatRoot($scheme, $root = null)
{
if (is_null($root)) {
if (is_null($this->cachedRoot)) {
// forcedRootが設定されている場合は優先されるみたい。
$this->cachedRoot = $this->forcedRoot ?: $this->request->root();
}
$root = $this->cachedRoot;
}
$start = Str::startsWith($root, 'http://') ? 'http://' : 'https://';
return preg_replace('~'.$start.'~', $scheme, $root, 1);
}
// forcedRootを設定するためのメソッドがある
public function forceRootUrl($root)
{
$this->forcedRoot = rtrim($root, '/');
$this->cachedRoot = null;
}
forcedRoot
が指定されていない場合は$_SERVER
から値を取得しているみたい。
public function getHost()
{
// ここの処理がいまいちわかってない
// プロキシを指定したときなどに関係ありそう
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
$host = $host[0];
// $_SERVERから取得している
} elseif (!$host = $this->headers->get('HOST')) {
if (!$host = $this->server->get('SERVER_NAME')) {
$host = $this->server->get('SERVER_ADDR', '');
}
}
Symfony2のコントローラについてまとめた(後半) - OTOBANK Engineering Blog
// $_SERVER['DOCUMENT_ROOT']
$request->server->get('DOCUMENT_ROOT');
// $_SERVERのインデックスのうち、命名がHTTP_*に該当するもの
// $_SERVER['HTTP_USER_AGENT']
$request->header->get('user-agent');
優先順位的には
- $this->forcedRoot
- $_SERVER['HTTP_HOST']
- $_SERVER['SERVER_NAME']
- $_SERVER['SERVER_ADDR']
になりそう。多分。
テスト(追記)
PHPUnitでテストを行う場合はphpunit.xml
でAPP_URL
を空にしておく。
$response= $this->get('foo/bar');
$response->assertStatus(200);
<php>
<server name="APP_URL" value=""/>
</php>
この記述がない場合、404がかえってきてテストが失敗してしまいました。