あるサイトにて,スマートフォン/タブレットからのアクセスについてはLaravelのルート自体を変更し対応したい,という要件がありました.
当初,Apacheのmod_rewriteで楽勝,と思っていたんですが,どハマりしてしまい;;
カッとなってLaravel5のMiddlewareで実装してみました.後悔はしていない.
2015/10/26 追記
- Middlewareを有効化する部分について書き忘れていました・・ご指摘ありがとうございますm(_ _)m
Middleware とは
HTTP Request に対して実行される小さなプログラムです.
CSRF対策のトークンチェック,ユーザ認証チェックなど,リクエストの全般に対して処理がしたい,なんて時に便利(ということがわかりました,今回).
リダイレクト内容
スマートフォン/タブレットからのアクセスの場合
- トップページ → /sptop
- その他のページ → /sp/元々のURLパス
とします.リダイレクト先もLaravelの守備範囲になります.
Middlewareを書く
ファイルの置き場所は app/Http/Middleware 配下になります.
中身はこんな感じ.
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Arr;
use Illuminate\Routing\Redirector;
class RedirectIfSmartphone {
/**
* The USER_AGENTs element.
*
* @var array
*/
protected $agents = [
"Android",
"iPhone",
"iPad",
"googlebot-mobile",
"iemobile",
"opera mobile",
];
public function handle($request, \Closure $next) {
if (!$this->isSmartphonePage($request) &&
$this->isSmartphone($request)) {
return redirect($this->generateSmartphonePage($request));
}
return $next($request);
}
protected function isSmartphonePage($request) {
return preg_match("#^(sptop|sp/)#", $request->path());
}
protected function isSmartphone($request) {
return preg_match("/(". implode("|", $this->agents) .")/",
Arr::get($_SERVER, 'HTTP_USER_AGENT', "PC"));
}
protected function generateSmartphonePage($request) {
$path = $request->path();
if (empty($path) || $path == "/") {
return "sptop";
}
return "sp/". $path;
}
}
- isSmartPhonePage で,現在アクセスしようとしているのがスマートフォン用ページかどうか判断し,
- USER_AGENTからスマートフォン/タブレットかを判断し
- リダイレクトすべきURLを生成し
- リダイレクト.
(1)と(2)の条件判断がFALSEであれば,PCからのアクセスまたはスマートフォン用ページを閲覧中,と判断し,そのまま本来の処理を続行させる,という感じです.
Middlewareを有効化する
クラスファイルを設置しただけではまだ機能しません.Laravelにその存在を知らしめる必要があります.
app/Http/Kernel.php にて,HTTPアクセスに対するMiddleware,ルーティングに関する Route Middleware の定義を行います.
具体的には Kernel.php 内の protected プロパティである $middleware に,処理すべきクラスを列挙していきます."stack" とコメントにある通り,この順番で実行されていくようなので,私の場合はメンテナンスモードチェックの直後に実行されるよう,2番目に追記しました.
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\RedirectIfSmartphone::class, // <== ここに追記
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
];
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
];
}
もし何かのお役に立てば幸いです.