Slide 1

Slide 1 text

Laravel 11 へアップグレード 15分 で終わるのか!? BABY JOB Takuya Katsusa PHP Conference Japan 2024

Slide 2

Slide 2 text

My Profile 勝佐 拓也 - かつさたくや  @kitkattsun0531 BABY JOB 株式会社(Bronzeスポンサー) 保活サイト「えんさがそっ♪」の開発保守 二児の父(9 ~ 11月に育休取得) 子ども大好きおじさん Laravelって なーに? ふ、、ふにゃ (知らんぞ)

Slide 3

Slide 3 text

施設を 探す 見学の 申込 園の魅力 を発信 見学の 受付 サービス紹介 (えんさがそっ ♪)

Slide 4

Slide 4 text

Laravel 11 待望のリリース!! 我々のチーム内は歓喜に包まれた

Slide 5

Slide 5 text

アップグレードガイドという神アイテムを 手にした一同 アップグレードに心を踊らせていた! さあ、アップグレードしてみよう!

Slide 6

Slide 6 text

Laravel 10 っ♪ は すでに アップグレードの 目安 15分!! Laravel Shift を見送った理由 ● 過去のアップグレードが比較的簡単だったこと ● 有料であること 引用:Laravel 11.x アップグレードガイド

Slide 7

Slide 7 text

PHP 8.3 っ♪ は すでに curl も問題なし! 引用:Laravel 11.x アップグレードガイド

Slide 8

Slide 8 text

ライブラリのアップグレード composer.json を 書き換えます

Slide 9

Slide 9 text

ローカルのアプリケーションを起動! Running migrations… 2024_12_22_142500_modify_hoikuens ...................... 647.05ms FAIL

Slide 10

Slide 10 text

ローカルのアプリケーションを起動! Running migrations… 2024_12_22_142500_modify_hoikuens ...................... 647.05ms FAIL local.ERROR: SQLSTATE[23502]: Not null violation: 7 ERROR: column "hoikuen_id" of relation "hoikuens" contains null values

Slide 11

Slide 11 text

ローカルのアプリケーションを起動! Running migrations… 2024_12_22_142500_modify_hoikuens ...................... 647.05ms FAIL local.ERROR: SQLSTATE[23502]: Not null violation: 7 ERROR: column "hoikuen_id" of relation "hoikuens" contains null values なん...だと...!? Why?

Slide 12

Slide 12 text

関連のテーブルを調査開始...30分経過 hoikuen_id カラムを VARCHAR に変えただけよ? Schema::table('hoikuens', function (Blueprint $table) { $table->string('hoikuen_id')->change(); ← }); お気づきだろうか... この時点で トークタイトルの 目安15分に 間に合ってない!

Slide 13

Slide 13 text

なるほど! つまり、変更分以外も認知して設定しなければならない 引用:Laravel 11.x アップグレードガイド Why?

Slide 14

Slide 14 text

Why Taylor Otwell

Slide 15

Slide 15 text

過去のマイグレーションファイルを 改変しなきゃいけないでしょう! それは御法度だろう!!

Slide 16

Slide 16 text

1回目のマイグレーション(テーブル作成) // 1回目 Schema::create('hoikuens', function (Blueprint $table) { $table->integer('hoikuen_id') ->nullable() ->default(0) ->comment('保育園ID'); (...以下省略) });

Slide 17

Slide 17 text

// 2回目 Schema::table('hoikuens', function (Blueprint $table) { $table->string('hoikuen_id') ->change(); }); 2回目のマイグレーション(型変更)

Slide 18

Slide 18 text

nullable()、default(0)、comment(’保育園ID’) が未設定になってる... 2回目のカラム変更による比較

Slide 19

Slide 19 text

// 1回目 Schema::create('hoikuens', function (Blueprint $table) { $table->integer('hoikuen_id')->nullable()->default(0)->comment('保育園ID'); }); // 2回目(型変更) Schema::table('hoikuens', function (Blueprint $table) { $table->string('hoikuen_id')->nullable()->default(0)->comment('保育園 ID')->change(); }); // 3回目(コメント変更) Schema::table('hoikuens', function (Blueprint $table) { $table->string('hoikuen_id')->nullable()->default(0)->comment('保育園の識別 ID')->change(); }); 当時のテーブル構成を再現しないのしんどい💦 なんだっけ? なんだっけ?

Slide 20

Slide 20 text

えんさがそチームは技術負債が見つかれば、 リファクタリングを積極的にやってくれる!! だからこそ テーブルのカラム名変更はいっぱいありました。 作業時間. . . . . . なんと 2時間!!

Slide 21

Slide 21 text

どこでテーブルの差分を確認した? えんさがそっ♪では データベースの定義書を自動生成しています! このおかげで差分がないか 簡単に確認することが できました! tbls はGo製の CLIツール

Slide 22

Slide 22 text

これで終わりだと 思った? ま゛だ ま゛だ あ゛る゛よ゛!!

Slide 23

Slide 23 text

config の 仕様が変わっていた! アップグレードガイドにも特に書いてなさそう たまたま、アップグレードに取り掛かる前に 奇跡的にこの記事に出会えました ❤ なおさんありがとうございます!とても参考になりました!

Slide 24

Slide 24 text

config ディレクトリが laravel(プロジェクト直下)にあるのは ご存知だと思います / └─ config └─ app.php ├─ auth.php ├─ cache.php └─ ...

Slide 25

Slide 25 text

Laravel 11 になると、 config が Laravel / framework にも作成されます v10.48.4 v11.7.0

Slide 26

Slide 26 text

ややこしいのが、 config が未設定だと laravel/framework の config で マージ されてしまうこと どういうことか? Why?

Slide 27

Slide 27 text

config('database.connections.sqlite'); = [ "driver" => "sqlite", "url" => null, "database" => "/laravel/database/database.sqlite", "prefix" => "", "foreign_key_constraints" => true, ] 例えば、config / database.php の sqlite を空白にします なんとconfigで参照すると、値が復活してます! つまり、未設定だとデフォルトの値で復活するということ! Why?

Slide 28

Slide 28 text

たまたま気づいたからいいけど... アップグレードガイドに書いてなかったような...

Slide 29

Slide 29 text

Why Taylor Otwell

Slide 30

Slide 30 text

Config の設定値をデフォルト値で マージするんじゃないよ!

Slide 31

Slide 31 text

設定ファイルなので慎重に調査を進めました💦 1. config の差分確認 2. php artisan tinker で config の値をチェック 3. Webアプリの動作確認 作業時間......なんと 4時間!!

Slide 32

Slide 32 text

一応、v11.11.0 で変更が入ったようです dontMergeFrameworkConfiguration メソッドを呼び出せば、 laravel/framework 側の config を参照しなくなるようです return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware) { // }) ->withExceptions(function (Exceptions $exceptions) { // }) ->create() ->dontMergeFrameworkConfiguration(); bootstrap/app.php

Slide 33

Slide 33 text

さあ 次はなんだ? (開き直り)

Slide 34

Slide 34 text

引用:Laravel 11.x アップグレードガイド

Slide 35

Slide 35 text

つまりログイン認証が通って必要であれば 再ハッシュして保存するということ ※再ハッシュといっても、 ハッシュ済みを再ハッシュ化するのではなく、 平文パスワードを新しい設定で ハッシュ化するということ Why?

Slide 36

Slide 36 text

なかなか強引な仕組み💦 実は理由があったようで... 引用:Laravel の PR

Slide 37

Slide 37 text

Laravel10 で bcrypt ラウンド数(パスワードハッシュ の計算強度)を 10 から 12 に増加する変更が行われた しかし、現在の Laravel の認証システムでは、ユーザー がログインする際に、ハッシュ設定が変更されても既存 のパスワードが再ハッシュされない これにより、セキュリティ上のリスクが生じる可能性が ある。たとえば、計算強度を増加させても、それが既存 のハッシュに適用されない場合、システム全体のセキュ リティの一貫性がなくなる (ビー・クリプト) パスワードの再ハッシュの実装経緯

Slide 38

Slide 38 text

どう考えてもトラブルになりそうなので で無効化することにしました 'rehash_on_login' => false,

Slide 39

Slide 39 text

理由は簡単で 実装者が意図せずに フレームワーク内でデータを 更新されるのが嫌だから

Slide 40

Slide 40 text

1. パスワードハッシュの計算強度の変更前である Laravel10 でユーザーを作成 2. 作成したユーザーでログインしてハッシュ値に変更 がないことを確認 作業時間......なんと 3時間!! 再ハッシュされないか確認

Slide 41

Slide 41 text

Why Taylor Otwell

Slide 42

Slide 42 text

そんな危ない設定を ログイン時に仕込むなよ!

Slide 43

Slide 43 text

もし再ハッシュが 有効になったら気になること

Slide 44

Slide 44 text

// ハッシュ済みか判定をせずに無条件でハッシュ化してしまうケース public function setPasswordAttribute($value) { $this->attributes['password'] = Hash::make($value); } ハッシュ済みの値を再ハッシュすることはない?

Slide 45

Slide 45 text

ハッシュ済みの値を再ハッシュすることはない? 対策 1:ハッシュ済みか判定処理を入れる 1 if ($this->hasher->needsRehash($hash)) { $this->attributes['password'] = Hash::make($value); }

Slide 46

Slide 46 text

ハッシュ済みの値を再ハッシュすることはない? 対策 2:キャストを利用してハッシュ化する protected $casts = [ 'password' => 'hashed', ];

Slide 47

Slide 47 text

サーバーリソースの消費が一時的に増加しない? 再ハッシュが必要であれば実行されるものではあるけど、   利用者数が多いWebアプリは影響受けそう

Slide 48

Slide 48 text

それでは皆さんお待ちかね アップグレードに かかった時間を発表します!

Slide 49

Slide 49 text

アップグレードにかかった時間 パスワードの再ハッシュ Config のマージ カラムの変更 26% 42% 32% 約 10 時間

Slide 50

Slide 50 text

1 5 分とは...

Slide 51

Slide 51 text

それでもやっぱり Laravel が大好き!!

Slide 52

Slide 52 text

だって laravelとMarvel 似てるんだもん だからアメコミ感を出してみた!

Slide 53

Slide 53 text

(ネタは置いといて...)

Slide 54

Slide 54 text

環境構築が簡 単

Slide 55

Slide 55 text

Web アプリケーション として扱える幅が大きい 認証・認可、メール・通知機能、 APIサポート、スケジューリング...etc

Slide 56

Slide 56 text

10時間で アップグレード できちゃう (ただしプロダクトによる)

Slide 57

Slide 57 text

強く当たっちゃったけど 私たちが仕事できているのは 皆様のおかげです

Slide 58

Slide 58 text

CREDITS: This presentation template was created by Slidesgo, including icons by Flaticon, infographics & images by Freepik thanks! 渾身の育休 note を執筆しました!

Slide 59

Slide 59 text

番外編! 引用:Laravel 11.x アップグレードガイド

Slide 60

Slide 60 text

diffIn 系メソッドは、float 型を返す! $startDate = new Carbon('2024-12-01'); $endDate = new Carbon('2024-12-03'); $startDate->diffInDays($endDate)); Carbon 2 の場合は、差が 2 Carbon 3 の場合は、差が 2.0 Why?

Slide 61

Slide 61 text

diffIn 系メソッドは、相対差分を返す! $startDate = new Carbon('2024-12-01'); $endDate = new Carbon('2024-12-03'); $endDate->diffInDays($startDate)); Carbon 2 の場合は、差が 2 Carbon 3 の場合は、差が - 2.0 Why? マイナス!?

Slide 62

Slide 62 text

Why Carbon Library

Slide 63

Slide 63 text

既存メソッドの仕様を 変えるんじゃないよ!

Slide 64

Slide 64 text

CREDITS: This presentation template was created by Slidesgo, including icons by Flaticon, infographics & images by Freepik thanks! 弊社はアドベントカレンダー実施中です