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ではエンジニアを募集しております。 興味のある方、ぜひご覧下さい。

【フロントエンドエンジニア】 [場所にとらわれず自社メディア成長に貢献したいフロントエンドエンジニア募集! - 株式会社WizのWebエンジニアの求人 - Wantedly]

【バックエンドエンジニア】 勤務地自宅を叶える!バックエンドエンジニアとして事業を成長させたい方募集 - 株式会社WizのWebエンジニアの求人 - Wantedly