Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

セッションのトークセッション / Traps for PHP session features...

uzulla
June 21, 2024

セッションのトークセッション / Traps for PHP session features in growing web apps

at: 【非公式】PHPカンファレンス福岡2024・前日Meetup
place: WeWork 大名(PR TIMES 福岡オフィス)
when: 2024/06/21
event site: https://prtimes.connpass.com/event/319375/

uzulla

June 21, 2024
Tweet

More Decks by uzulla

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ w JEV[VMMB 9 (JU)VC :PVUVCF FUDʜ w ྲྀ͠ͷ1)1FS w

    135*.&4ʹ͓͍ͯ͸ۀ຿ҕୗͰԿͰ΋԰ w ͜ͱ͠͸΄΅ಉ໊τʔΫམͪͨͷͰɺ ͜͜Ͱڙཆ ܰྔԽ൛Ͱ͢
  2. ηογϣϯͱ͸ʁ w εςʔτϨε ঢ়ଶ ͳIUUQͷ௨৴ʹεςʔτΛ࣋ͪࠐΉ෺ w ʁʁ )551௨৴ͷఆٛΛड़΂Α ࢲʮΨϠͯ͘͠Εʯ w

    ͨͱ͑͹ϩάΠϯঢ়ଶͳͲΛѻ͏ w ΢ΣϒΞϓϦέʔγϣϯʹ͓͍ͯ͸ɺ΄΅ඞਢ w ʁʁʮݱࡏ͸+XUͳͲ͕͋Δʯ ʁʁʮϓϩͷํ͸ɺʰ͍ͭ͜ղͬͯͳ͍ͳʱͳͲͱ ϋογϡλάQSUJNFT@EFWͰπΠʔτ͍ͯͩ͘͠͞ʯ
  3. εςʔτ ঢ়ଶ ͱ͸ʁ w $_GET['page'] ݱࡏͷϖʔδ ౳΋εςʔτͱ͍͑Δ w ͨͩɺͦΕ͸ൿಗ৘ใͰ͸ແ͍ ࣄ͕ଟ͍

    w 63-͸γΣΞ͞ΕͨΓϩάͳͲʹग़ͯ͠·͏͕͔·Θͳ͍ w ͍ͬͦ63-ʹ͋ͬͨ΄͏͕γΣΞग़དྷͯศར w 1045΋ɺอ࣋ͯ͠JOQVUUZQFIJEEFO͸εςʔτ w ֬ೝը໘ͱͦͷઌͷૹ৴ը໘ͳͲ w ૹ৴ऀͳΒ஌͍ͬͯͯ΋͔·Θͳ͍
  4. ҆શͳঢ়ଶͱ͸ʁ w ໪࿦Θ͟ͱ΍Ε͹ผ͕ͩ w ֎෦͔Β w ِ଄Ͱ͖ͳ͍ w վ͟ΜͰ͖ͳ͍ w

    Ͱ͖Ε͹ ӾཡɾਪଌͰ͖ͳ͍ w ֎෦ͱ͸ɺ৴པ͞Εͨαʔόʔ಺෦Ҏ֎Λࢦ͢ w ֎෦͸ୈࡾऀͷΈͳΒͣɺΞΫηε͢ΔϢʔβʔ΋ؚΉ
  5. 1)1ͷ࠷ߴػೳ$_SESSION w 1)1ʹ͸ɺ؆୯ศརͳηογϣϯػೳ͕࠷ॳ͔Β͋Δ w ʮ$PPLJF ౳ Ͱ*%Λ࣋ͪɺ৘ใ͸αʔόʔʹอଘ͢ΔʯλΠϓ w ଞݴޠʹൺ΂ɺ࢖͍࢝ΊΔͷ͕ɺ͘͢͝؆୯Ͱ جຊ

    ҆શ w ετϨʔδͷ੾Γସ͑΋؆୯ pMFɺSFEJTɺNZTRMɺࣗ࡞ʜ w Ωϟογϡͱͯ͠΋࢖͑ͪΌͬͨΓͳΜͩΓ w ग़དྷΔࣄʹ΄΅੍ݶ͕ͳ͍ɺศར͗͢ʂ ʁʁ
  6. ϩάΠϯػೳ স Λ࣮૷ͯ͠ΈΑ͏ ʁ session_start(); // === function getUserIdOrFalse($id, $pass){

    // ద࣮ٓ૷ͯͩ͋͘͠͠() return $id==="user"&&$pass==="pass" ? 1 : false; } if($user_id = getUserIdOrFalse(@$_POST['id'], @$_POST['pass'])){ $_SESSION['user_id'] = $user_id; } // === if(@$_SESION['user_id']){ // ͜ͷˏͷҙຯ͕෼͔Δਓ͸खΛ͍͋͛ͯͩ͘͞ // ϩάΠϯதʂ }
  7. ԿͰ΋ೖΔͱ͍͏͜ͱ͸ԿͰ΋ೖΔ w ͨͱ͑͹ɺ$.4΍Χʔτͷ৘ใͱ͔΋ೖΔ $_SESSION['login_user'] = new LoginUser(256); ͱ͔ $_SESSION['cart_items'][] =

    new CartItem(134); w ʁʁʁʮ%50ʹ͠·ͨ͠ʂʯࢲʮ͜Ε͸ʜ͏Μʜͪΐͬͱ͕ͪ͏͔ͳʜʯ w Ұݟศར͕ͩɺΘ͔ͬͯ΍Βͳ͍ͱϩΫͳ͜ͱʹͳΒͳ͍
  8. ݁Ռ w ʁʁʮҰମ͜ͷ$_SESSION͸Ͳ͏͍͏ܗͳΜͩʜ ͜ͷ%50͸ࣺ͍͍ͯͯͷ͔ʜʁʯ w ఆٛͷͳ͍഑ྻ͸த਎͕%50Ͱ͋ͬͯ΋ɺͱʹ͔͘Ϡό͍ w 1)1ͷηογϣϯ͸શ෦ BUPNJDʹ ૸ࠪมߋ

    ϚΠάϨʔγϣϯ ͢Δ͜ͱ͸ جຊతʹ͸ Ͱ͖ͳ͍ ͓͡͞Μʹ͸ඞࡴཪٕ͸͋Δ w ͳͷͰϚΠάϨʔγϣϯ ΍૟আ ͕Ͱ͖ͳ͍ w ઌഐʮ͜͜͸͞ΘΒͳ͍Ͱ͓͍͍ͯͩ͘͞ʯ ޙഐʮഐʯ
  9. ྫ new $session_instance = new MySession();//Ͱɺ։࢝͢Δͱͯ͠ # NG (SessionͷதʹੜͷΫϥεΠϯελϯε) $_SESSION['my_session']

    = $session_instance; // อଘ $session_instance = $_SESSION['my_session']; // औΓग़͠ # Better (Sessionͷத͸Ϧςϥϧͷ഑ྻ) $_SESSION['my_session'] = $session_instance->toArray(); // อଘ $session_instance = new MySession($_SESSION); // औΓग़͠
  10. session_start(); class A { public int $id = 1; }

    $a = $_SESSION['a'] ?? new A(); $a->id = 123; $_SESSION['a'] = $a;
  11. "Λมߋͯ͠ΈΔ class A { public int $id = 1; }

    ↓ όʔδϣϯΞοϓͰϓϩύςΟ͕૿͑Δ class A { public int $id = 1; public int $name = 'taro'; }
  12. ΋Ͳͤͳ͘ͳΔ Fatal error: Cannot use string as default value for

    property A::$name of type int in /.../some.php on line 7 w 1)1VOTFSJBMJ[Fͷ࢓༷Ͱ͜͏ͳ͍ͬͯΔ
  13. ͜͏ͳΔ ૿͑Δ͚ͩͳΒ class Session { public function __construct( public ?int

    $id = null, public ?string $name = '', ){} public function _toArray(){ return (array)$this; // ΋ͬͱ͜͜͸ཱ೿ʹॻ͘΂͖ } public function __destruct(){ $_SESSION['session'] = $this->_toArray(); session_commit(); // খωλ͕ͩɺ͜Ε͕ͳ͍ͱอଘ͞Εͳ͍͜ͱ͕͋Δ } } ͨͩ͠ɺ͜Ε͸͓͡ςΫͰ͢ਅࣅΔͳ
  14. ηογϣϯͷ%50ྫ class MySession { const LATEST_VERSION = 3; public function

    __construct( public int $version, public int $user_id, public int $account_id, public string $status, public string $name, ) {} }
  15. // ͋Γ͏ΔΑ͏ͳɺηογϣϯͷܗঢ় $session_1 = [ "version" => 1, "id" =>

    123 ]; $session_2 = [ "version" => 2, "user_id" => 123, "account_id" => 123, "status" => 'active' ]; $session_3 = [ "version" => 3, "user_id" => 456, "account_id" => 456, "status" => 'active', "name" => 'John Doe' ];
  16. class SessionTransformer { public function __construct(private PDO $pdo){} // όʔδϣϯ1ͷηογϣϯΛόʔδϣϯ2ͷܗঢ়ʹม׵͢ΔελςΟοΫϝιου

    public static function transformVer1ToVer2(array $session) { return [ 'version' => 2, 'user_id' => $session['id'], // ϦωʔϜ ͍ͯ͠Δ 'status' => 'active' // v1ʹͳ͍PropΛσϑΥϧτΛೖΕΔέʔε ]; } // ಉɺV2 to V3 public static function transformVer2ToVer3($session) { return [ 'version' => 3, 'user_id' => $session['user_id'], 'status' => $session['status'], 'name' => User::getName($pdo, $session['user_id']), // DBҾ͘ ]; } // ࣍ͷϖʔδʹͭͮ͘
  17. ϧʔϓͯ͠ϚΠάϨʔγϣϯ͍ͯ͘͠ function transformSession(array $session) :MySession { // ࠷৽൛·Ͱϧʔϓ͢Δ while ($session['version']

    < MySession::LATEST_VERSION) { $session = match ($session['version']) { 1 => SessionTransformer::transformVer1ToVer2($session), 2 => SessionTransformer::transformVer2ToVer3($session), // ϚΠάϨͰ͖ͳ͍ͳΒɺ֎෦ͰϩάΞ΢τѻ͍͢ΔͳͲ͢Δ default => throw new BrokenSessionException('boo'), }; } // লུ͢Δ͕ɺnewͰ͖ͳ͍৔߹΋ΤϥʔॲཧΛ return new MySession(...$session); }
  18. ๲ΕΔηογϣϯ register_shutdown_function(function(){ if( session_status() === PHP_SESSION_ACTIVE && isset($_SESSION) && is_array($_SESSION)

    && count($_SESSION) === 0 ){ @session_destroy(); //ۭͷηογϣϯΛഁغ } }); register_shutdown_function͸4IVUEPXO࣌ʹݺ͹ΕΔϋϯυϥొ࿥ auto_prepend_fileͰ͍ΕΔ͜ͱ΋Ͱ͖Δ ͜Ε΋͓͡ςΫͰ͢ɺਅࣅͳ͍Ͱ