九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、Laravelを使った開発ではリダイレクトの場合など、しばしばある特定のURLを取得する必要が出てくる場合があります。
もちろんURLを直接 https://****.com/test1/test2
というように直にコーディングしてもいいのはいいのですが、LaravelにはパラメータつきでURLを取得したりルーティングやコントローラーからもURLが取得できるため、これらのテクニックを知っているとコーディングがとても楽になります。
また、特にルーティング名を使ってURLを取得しておくと、その後サイト構成が変わってしまってもそのままURLは自動的に切り替わりますし保守的にもプラスな部分もあります。
ということで、今回はLaravelでURLを取得する全実例をお届けします。
ぜひ開発の参考にしてください。
※ Laravelのバージョン: 5.7
目次
実行環境について
今回紹介する全てのコードはhttp://example.test
というローカルサイトで実行しています。そのため、ご自身の環境で実行した場合とドメイン部分が違ってきますのでご注意ください。
基本的なURLの取得方法: url()
まずLaravelで一番基本的なURLの取得方法はヘルパー関数のurl()
を使ったものです。
トップページのURLを取得する
url()
の引数に空白、もしくは/
を指定するとトップページを取得することができます。
echo url('');
echo url('/');
ページを指定してURLを取得する
例えば、http://example.test/xxx.html
というURLを取得したい場合です。
この場合、url()
の引数に直接xxx.html
を指定します。
echo url('xxx.html');
階層が深いページを指定してURLを指定する
例えば、http://example.test/xxx/yyy/zzz
というURLを取得したい場合です。同じく引数に取得したい階層を指定します。
echo url('xxx/yyy/zzz');
もしくは、次のように第2引数に配列を指定することで取得することもできます。
echo url('/', ['xxx', 'yyy', 'zzz']);
パラメータをつけたURLを取得する
例えば、http://example.test/xxx?key=value
というURLを取得する場合です。
echo url('xxx?key=value');
https://から始まるURLを取得する
例えば、https://example.test
というURLを取得する場合です。
この場合、第3引数にtrue
を指定します。
echo url('/', null, true);
パラメータを含まない現在のURLを取得する: current()
例えば、現在のURLが"http://example.test/xxx?key=value"
だったとして、"http://example.test/xxx"
を取得する場合です。
echo url()->current();
パラメータを含む現在のURLを取得する: full()
例えば、現在のURLが"http://example.test/xxx?key=value"
だったとして、 そのままパラメータを含めた"http://example.test/xxx?key=value"
を取得する場合です。
echo url()->full();
直前にリクエストされたURLを取得する: previous()
echo url()->previous();
ルーティングを使ったURLの取得
全120種類!Laravel5.6ヘルパー関数実例 の route()でルート名を指定してURLを取得する をご覧ください。
コントローラーを使ったURLの取得
全120種類!Laravel5.6ヘルパー関数実例 の action()でコントローラーとアクションからURLを取得する をご覧ください。
署名つきURLを取得する
例えば次のような流れを考えてください。
- パスワードの変更申請をする
- 署名つき(一意な文字列がついた)URLがメール送信されてくる
- そのURLにアクセスするとパスワード変更ができる
この場合の2番目の項目で必要になる署名付きURLを作成する方法です。
URLを取得する方法
ではこのURLの取得方法です。
まずルーティングを設定しましょう。
Route::get('user/password_reset', 'User\HomeController@password_reset')->name('user.password_reset');
そして、URL::signedRoute()
を実行します。
use Illuminate\Support\Facades\URL;
echo URL::signedRoute('user.password_reset', ['user_id' => 1]);
これを実行すると次のようなURLを発行されることになります。
http://example.test/user/password_reset?user_id=1&signature=757ae5fea4f5b7cecc9aa741a378d4fc25aeaac758c27d9d06f92c562a660faf
このsignature
の部分が署名で、一意な文字列になり、後ろのパラメータが変わると文字列は変更になります。
また、制限時間がある署名URLを取得することもできます。(つまり、「このリンクの有効時間は24時間です」という時間制限があるURLになります)
use Illuminate\Support\Facades\URL;
$expire = now()->addHours(24); echo URL::temporarySignedRoute( 'user.password_reset', // ルーティング名 $expire, // 有効期限(この場合24時間) ['user_id' => 1] // パラメータ );
実際にこのコードを実行したものが以下になります。
http://example.test/user/password_reset?expires=1542652227&user_id=1&signature=4bcc7e874128d6f10071f3dd746cde4bf1a92065d44ca2b1ef0ce2c1fe6d4366
取得した署名つきURLが有効かチェックする
ルーティング内でチェックする方法
ルーティング内でhasValidSignature()
を使うことでURLが有効かチェックすることができます。
Route::get('user/password_reset', function (\Illuminate\Http\Request $request) { if(!$request->hasValidSignature()) { return redirect('/'); // 無効の場合はリダイレクト } })->name('user.password_reset');
ミドルウェアを使う方法
ルーティング内でチェックをするとコードが増えてしまい可読性が悪くなる場合がありますので、そんな場合は専用のミドルウェアを使って署名URLが有効か無効かをチェックしましょう。
まず、app/Http/Kernel.php
を開いて$routeMiddleware
にValidateSignature
を追加します。(ちなみに私の環境ではすでに登録されていました)
protected $routeMiddleware = [ // 省略 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, ];
これでsigned
が使えるようになりましたので、ルーティングで次のようにするといいでしょう。
Route::get('user/password_reset', 'User\HomeController@password_reset') ->name('user.password_reset') ->middleware('signed');
この場合、もし無効なURLにアクセスされたら403コードが返されます。
もしリダイレクトしたい場合は以下のように独自のミドルウェアを作成して使うといいでしょう。
<?php namespace App\Http\Middleware; use Closure; class ValidationSignatureRedirect { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if ($request->hasValidSignature()) { return $next($request); } return redirect('/'); } }
ルーティングのパラメータにに初期値を設定する
例えば、もしログインしているときはURLに以下のようにユーザー名が入ってくるとします。
- http://example.test/username/xxx.html
- http://example.test/username/yyy/zzz
この場合、ルーティングは次のようになります。
Route::get('{username}/xxx.html', 'HomeController@xxx')->name('xxx'); Route::get('{username}/yyy/zzz', 'HomeController@yyy_zzz')->name('yyy.zzz');
ではミドルウェアを使ってこのデフォルト値を次のルールで設定しましょう。
- ログインしている場合 ・・・ ユーザー名
- ログインしていない場合 ・・・ guest
まず専用のミドルウェアをつくります。
php artisan make:middleware SetDefaultUserName
そして、作成されたapp/Http/Middleware/SetDefaultUserName.php
を開いて中身を以下のように変更します。
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\URL; class SetDefaultUserName { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $username = (auth()) ? auth()->user()->name : 'guest'; URL::defaults(['username' => $username]); return $next($request); } }
そして、このミドルウェアをapp/Http/Kernel.php
へ登録します。
protected $middlewareGroups = [ 'web' => [ // 省略 SetDefaultUserName::class, ], // 省略 ];
※ ちなみにドキュメントには “route middleware” と書かれていますが$routeMIddleware
へ登録してもエラーが発生してしまいます。
そして、先ほどのルーティングをグループ化してミドルウェアを適用しましょう。
Route::middleware('default_user_name')->group(function(){ Route::get('{username}/xxx.html', function(){})->name('xxx'); Route::get('{username}/yyy/zzz', function(){})->name('yyy.zzz'); });
これで、route()
に初期値が設定されました。
echo route('xxx');
これを実行するとパラメータなしでも以下のようになります。
(ログインしていない時)
http://example.test/guest/xxx.html
(ログインしている時)
http://example.test/taro/xxx.html