LoginSignup
17

More than 5 years have passed since last update.

[メモ] Laravel5 でPC/スマートフォンサイトの振り分けを行う

Last updated at Posted at 2015-10-14

あるサイトにて,スマートフォン/タブレットからのアクセスについてはLaravelのルート自体を変更し対応したい,という要件がありました.
当初,Apacheのmod_rewriteで楽勝,と思っていたんですが,どハマりしてしまい;;

カッとなってLaravel5のMiddlewareで実装してみました.後悔はしていない.

2015/10/26 追記

  • Middlewareを有効化する部分について書き忘れていました・・ご指摘ありがとうございますm(_ _)m

Middleware とは

HTTP Request に対して実行される小さなプログラムです.
CSRF対策のトークンチェック,ユーザ認証チェックなど,リクエストの全般に対して処理がしたい,なんて時に便利(ということがわかりました,今回).

リダイレクト内容

スマートフォン/タブレットからのアクセスの場合

  • トップページ → /sptop
  • その他のページ → /sp/元々のURLパス

とします.リダイレクト先もLaravelの守備範囲になります.

Middlewareを書く

ファイルの置き場所は app/Http/Middleware 配下になります.
中身はこんな感じ.

app/Http/Middleware/RedirectIfSmartphone.php
<?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;
    }
}
  1. isSmartPhonePage で,現在アクセスしようとしているのがスマートフォン用ページかどうか判断し,
  2. USER_AGENTからスマートフォン/タブレットかを判断し
  3. リダイレクトすべきURLを生成し
  4. リダイレクト.

(1)と(2)の条件判断がFALSEであれば,PCからのアクセスまたはスマートフォン用ページを閲覧中,と判断し,そのまま本来の処理を続行させる,という感じです.

Middlewareを有効化する

クラスファイルを設置しただけではまだ機能しません.Laravelにその存在を知らしめる必要があります.
app/Http/Kernel.php にて,HTTPアクセスに対するMiddleware,ルーティングに関する Route Middleware の定義を行います.

具体的には Kernel.php 内の protected プロパティである $middleware に,処理すべきクラスを列挙していきます."stack" とコメントにある通り,この順番で実行されていくようなので,私の場合はメンテナンスモードチェックの直後に実行されるよう,2番目に追記しました.

app/Http/Kernel.php
<?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,
    ];
}

もし何かのお役に立てば幸いです.

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17