今回はPHPのLaravelで既存画像のWebP化及び切替表示について実装例を紹介してみようと思います。
目的
記事の画像をWebP化することによって記事の表示スピードを早くする。
WebP(うぇっぴー)とは
軽量の新画像形式で開発したグーグルによると、画像をWebP化することによって可逆形式ではpngの26%、不可逆形式では25〜34%もファイルサイズを減らすことができると紹介されています。 詳細については[こちら]をご覧ください。
Chromeブラウザのみの対応だったWebP 画像が Edge, Firefox 等の最新版で使用でき、8割近いブラウザで使えるようになってきたそうです。 WebP対応ブラウザ確認は[こちら]をご覧ください。
たくさん画像を使う記事サイトで高速化のためにWebPを使うことが有効ですが、サポートしないブラウザもあるのでWebP対応ブラウザはWebPを、非対応ブラウザは既存画像(jpegやpng等)を利用するなど切替表示の必要があります。
現状
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ではエンジニアを募集しております。 興味のある方、ぜひご覧下さい。