Wiz テックブログ

Wizは、最新のIoTやICTサービスをお客様に届ける「ITの総合商社」です。

Laravelで既存画像のWebP対応

今回はPHPのLaravelで既存画像のWebP化及び切替表示について実装例を紹介してみようと思います。

目的

記事の画像をWebP化することによって記事の表示スピードを早くする。

WebP(うぇっぴー)とは

軽量の新画像形式で開発したグーグルによると、画像をWebP化することによって可逆形式ではpngの26%、不可逆形式では25〜34%もファイルサイズを減らすことができると紹介されています。 詳細については[こちら]をご覧ください。

Chromeブラウザのみの対応だったWebP 画像が Edge, Firefox 等の最新版で使用でき、8割近いブラウザで使えるようになってきたそうです。 WebP対応ブラウザ確認は[こちら]をご覧ください。

たくさん画像を使う記事サイトで高速化のためにWebPを使うことが有効ですが、サポートしないブラウザもあるのでWebP対応ブラウザはWebPを、非対応ブラウザは既存画像(jpegpng等)を利用するなど切替表示の必要があります。

現状

1) 画像ファイルURL

画像ファイルURLは、認証制御の理由で実際のファイルURLを利用しないで下記のようにAPIで取得します。

src="https://xxxxx.jp/api/image/1"
2) 画像ファイルの情報

画像ファイルの情報は下記のようにDBのテーブルに格納しています。

id name context_type created_at
1 image01.jpg image/jpeg 2018-02-08 16:13:38
2 image01.png image/png 2018-02-08 16:13:59

App\Models\ImageFileには上記テーブルの項目が入っています。

実装手順

1) 画像の新規登録&変更登録時対応

管理画面で画像の新規登録&変更登録する際に、アップロードされた画像からWebP画像を作成し別途保存する処理を追加

2) 画像表示の切替処理

サイトで画像を表示する際に、WebP対応ブラウザかどうか判定してWebP対応ならWebP画像、非対応なら既存の画像タイプを表示するように切替処理を.htaccessで設定

3) 既存画像の対応

バッチで一括で既存画像をWebp化する仕組みを作る

前提条件

1) libwebpのインストール

下記のコマンドで

$ php -r 'print_r(gd_info());'

下記が表示される場合、サポートされていないのでlibwebpライブラリをインストールする必要があります。

[WebP Support] => 0 
或は
[WebP Support] => 

下記のコマンドでlibwebpをインストール

$ sudo yum --enablerepo=remi-php73 install php73-gd

下記のコマンドでapache再起動

$ service httpd reload

下記のコマンドで確認

$ php -r 'print_r(gd_info());'

下記が表示されればWebPがサポートされていると考えられます。

[WebP Support] => 1

2) LaravelにIntervention Imageを追加

Composer Installation

$ php composer.phar require intervention/image

config/app.phpにパッケージを登録

'providers' => [
    Intervention\Image\ImageServiceProvider::class,
]

'aliases' => [
    'Image' => Intervention\Image\Facades\Image::class,
]

下記のコマンドで、configフォルダ内にimage.phpという設定ファイルが作成されます。

Laravelでconfigファイルを公開(作成)する場合

$ php artisan vendor:publish --provider="Intervention\Image\ImageServiceProviderLaravelRecent"

Laravelのバージョンが4以下の場合

$ php artisan config:publish intervention/image

これでLaravelでのIntervention Imageインストールは完了です。

              

1. 画像の新規&変更登録時対応

ルート

// 画像アップロード
Route::post('/image', 'ImageController@uploadImage');
// 画像取得
Route::get('/image/{id}', 'ImageController@getImage);

blade

Laravel:
{{ Form::file('image') }}

html:
<input name="image" type="file">

Controller

ImageController.php

<?php 
use App\Models\ImageFile;
use Intervention\Image\ImageManagerStatic as Image;

//画像アップロード
public function uploadImage(Request $request) {
        //  画像情報を取得
        $file = $request->file('image');
        
         // 画像情報をDBに保存
        $ImageFile = new ImageFile();
        $ImageFile->name            = $file->getClientOriginalName();
        $ImageFile->context_type  = $file->getMimeType();
        $ImageFile->created_at     = Carbon::now();
        $ImageFile->save();

        // storageフォルダ以下に画像を保存(物理的なファイルのURLがないパターン)
        $file->move(storage_path(config('system.path.imgae')), $ImageFile->id);

        // 画像を読み込む: make()
        $path = storage_path(config('system.path.imgae')).$ImageFile->id;
        $image = \Image::make($path);

        // WebPを作成
        $webp_path = storage_path(config('system.path.imgae').$ImageFile->id .'.webp');
        $image->save($webp_path);
}

2. 画像表示の切替処理

.htaccess処理

.htaccessで画像取得のURLが /image/{id}の場合、/image/{id}?webp=1にリダイレクトさせることによって、 ブラウザによって自動的に切り替えできるようにします。

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_URI} ^/image/[0-9]*$
    RewriteCond %{QUERY_STRING} !webp=[^&]*
    RewriteRule ^(.*)$ $1?webp=1 [L]
</IfModule>

.htaccessはできることが多いので良かったら[こちら]も参考に見てください。

画像取得処理

.httaccessのリダイレクトでURLに追加した?webp=1を取得し、対応ブラウザかWebPだったらWebPに切り替えるようにします。

ImageController.php

<?php
use App\Models\ImageFile;
use Intervention\Image\ImageManagerStatic as Image;

public function getImage(Request $request, $id) {
    
    // ファイル情報を取得
    $imageFile = ImageFile::find($id);
    if (!$imageFile) {
        return;
    }

    $contextType = $imageFile->context_type;
    $fileName = $imageFile->id;
    
    // 対応ブラウザかWebPだったらWebPに切り替える
    $webp = $request->input('webp');
    if($webp == true){
        $contextType = 'image/webp';
        $fileName = $imageFile->id . '.webp';
    }

    // ファイルをダウンロードさせる
    $headers = array('Content-Type' => $contextType, 'Content-Disposition' => 'inline; filename="'.$imageFile->name.'"');
    $pathToFile = storage_path(config('system.path.imgae')).$fileName;
    $response   = response()->file($pathToFile, $headers);

    return $response;
}

3. 既存画像のWebp化対応

バッチで一括で記事既存画像のWebp化の仕組みを作ります。

app/Console/Kernel.php

<?php
use App\Console\Commands\CreateWebpFile;
class Kernel extends ConsoleKernel
{
    protected $commands = [
        CreateWebpFile::class,
    ];
}

下記のコマンドでクラスを作成

$ php artisan make:command CreateWebpFile

app/Console/Commands/CreateWebpFile.php

<?php
namespace App\Console\Commands;
use Illuminate\Support\Facades\DB;
use Intervention\Image\ImageManagerStatic as Image;

class Kernel extends ConsoleKernel
{
    protected $signature = 'CreateWebpFile';
    
     public function handle()
    {
        $imgaeFile= DB::table('imgae_file')->get();
        if (!$imgaeFile) {
            return;
        }

        foreach ($imgaeFile as $image) {
            // id取得
            $imageId = $image->id;

            $Path = storage_path(config('system.path.imgae')) . $imageId;
            $PathWebp = $Path . '.webp';

            if(file_exists($Path) && !file_exists($PathWebp)){
                // webp保存
                $image = Image::make($Path)->orientate();
                $image->save($PathWebp);
            }
        }
    }
}

プロジェクトディレクトリに入って、下記のコマンドでWebPファイルが作成されました。

$ php artisan CreateWebpFile

さいごに

バックエンドエンジニアとしてWizに入社後、アプリケーション実装だけでなくSEO対策、SSL更新、メールサーバー構築、WEBサーバー構築など幅広く挑戦・成長できるチャンスをたくさんもらいました。

Wizではエンジニアを募集しております。 興味のある方、ぜひご覧下さい。

careers.012grp.co.jp