Share
Embed
セッションのトークセッション / 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
Transcript
45 slides
-
ηογϣϯͷτʔΫηογϣϯ w V[VMMB w ʲඇެࣜʳ1)1ΧϯϑΝϨϯεԬɾલ.FFUVQ w 8F8PSLେ໊ 135*.&4ԬΦϑΟε w
w IUUQTQSUJNFTDPOOQBTTDPNFWFOU -
ࣗݾհ w JEV[VMMB 9 (JU)VC :PVUVCF FUDʜ w ྲྀ͠ͷ1)1FS w
135*.&4ʹ͓͍ͯۀҕୗͰԿͰ w ͜ͱ͠΄΅ಉ໊τʔΫམͪͨͷͰɺ ͜͜Ͱڙཆ ܰྔԽ൛Ͱ͢ -
ηογϣϯͱʁ w εςʔτϨε ঢ়ଶ ͳIUUQͷ௨৴ʹεςʔτΛ࣋ͪࠐΉ w ʁʁ )551௨৴ͷఆٛΛड़Α ࢲʮΨϠͯ͘͠Εʯ w
ͨͱ͑ϩάΠϯঢ়ଶͳͲΛѻ͏ w ΣϒΞϓϦέʔγϣϯʹ͓͍ͯɺ΄΅ඞਢ w ʁʁʮݱࡏ+XUͳͲ͕͋Δʯ ʁʁʮϓϩͷํɺʰ͍ͭ͜ղͬͯͳ͍ͳʱͳͲͱ ϋογϡλάQSUJNFT@EFWͰπΠʔτ͍ͯͩ͘͠͞ʯ -
εςʔτ ঢ়ଶ ͱʁ w $_GET['page'] ݱࡏͷϖʔδ εςʔτͱ͍͑Δ w ͨͩɺͦΕൿಗใͰແ͍ ࣄ͕ଟ͍
w 63-γΣΞ͞ΕͨΓϩάͳͲʹग़ͯ͠·͏͕͔·Θͳ͍ w ͍ͬͦ63-ʹ͋ͬͨ΄͏͕γΣΞग़དྷͯศར w 1045ɺอ࣋ͯ͠JOQVUUZQFIJEEFOεςʔτ w ֬ೝը໘ͱͦͷઌͷૹ৴ը໘ͳͲ w ૹ৴ऀͳΒ͍͔ͬͯͯ·Θͳ͍ -
ػີɾൿಗ͕ඞཁͳεςʔτ w ্هͱҟͳΓɺൿಗ͕ඞཁͰɺվ͟Μɾِͤͨ͘͞ͳ͍ใ͋Δ w ྫݱࡏϩάΠϯதͷ ෦తͳ Ϣʔβʔ*% w γϣοϐϯάΧʔτใͳͲɺᴥᴪ͕ڐ༰Ͱ͖ͳ͍ͷ w
վ͟Μͤͨ͘͞ͳ͍ɺڞ༗͠ͳ͍ใΛηογϣϯʹೖΕΔ w ҆શͳঢ়ଶʹͳΔ -
҆શͳঢ়ଶͱʁ w Θ͟ͱΕผ͕ͩ w ֎෦͔Β w ِͰ͖ͳ͍ w վ͟ΜͰ͖ͳ͍ w
Ͱ͖Ε ӾཡɾਪଌͰ͖ͳ͍ w ֎෦ͱɺ৴པ͞Εͨαʔόʔ෦Ҏ֎Λࢦ͢ w ֎෦ୈࡾऀͷΈͳΒͣɺΞΫηε͢ΔϢʔβʔؚΉ -
1)1ͷ࠷ߴػೳ$_SESSION w 1)1ʹɺ؆୯ศརͳηογϣϯػೳ͕࠷ॳ͔Β͋Δ w ʮ$PPLJF Ͱ*%Λ࣋ͪɺใαʔόʔʹอଘ͢ΔʯλΠϓ w ଞݴޠʹൺɺ͍࢝ΊΔͷ͕ɺ͘͢͝؆୯Ͱ جຊ
҆શ w ετϨʔδͷΓସ͑؆୯ pMFɺSFEJTɺNZTRMɺࣗ࡞ʜ w Ωϟογϡͱͯ͑ͪ͠ΌͬͨΓͳΜͩΓ w ग़དྷΔࣄʹ΄΅੍ݶ͕ͳ͍ɺศར͗͢ʂ ʁʁ -
ϩάΠϯػೳ স Λ࣮ͯ͠ΈΑ͏ ʁ 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']){ // ͜ͷˏͷҙຯ͕͔ΔਓखΛ͍͋͛ͯͩ͘͞ // ϩάΠϯதʂ } -
ศརʂʂʂ w 1)1ϩάΠϯΛଈ࣮ग़དྷͯศར w $_SESSION୯ͳΔ ʁ ྻͳͷͰɺෳࡶͳࣝෆཁʂ session_start(); //== $_SESSION['name']
= getUserName($user_id); //== echo $_SESSION['name'] ?? ’ະϩάΠϯ’; -
ԿͰೖΔͱ͍͏͜ͱԿͰೖΔ w ͨͱ͑ɺ$.4Χʔτͷใͱ͔ೖΔ $_SESSION['login_user'] = new LoginUser(256); ͱ͔ $_SESSION['cart_items'][] =
new CartItem(134); w ʁʁʁʮ%50ʹ͠·ͨ͠ʂʯࢲʮ͜Εʜ͏Μʜͪΐͬͱ͕ͪ͏͔ͳʜʯ w Ұݟศར͕ͩɺΘ͔ͬͯΒͳ͍ͱϩΫͳ͜ͱʹͳΒͳ͍ -
େ࠷ॳʹ౿Ή w ҉ʹεΩʔϚϨε%#ͱ͔ͯͭ͠ΘΕ͍ͯΔ͜ͱ͕ଟ͍ w FY%#ʹΞΫηε͢Δͷ໘ͩ͠ɺ໊લΛೖΕ͓ͯ͜͏ w εΩʔϚ͕มΘ͔ͬͨΒɺࠪతʹશσʔλΛमਖ਼ͱ͔ग़དྷͳ͍ w ͢Ͱʹଘࡏ͢Δηογϣϯίʔυมߋͱؔͳ͍ w
ͦΜͳ͜ͱͨ͠ΒϢʔβʔӨڹ͕ग़Δ w ࢦఆϢʔβʔͷΈڧ੍ϩάΞτͱ͔ ެࣜʹ ͳ͍ -
ݱ࣮ੈքͷཁ݅ w ʁʁʮΫϥε%50ೖΔ͔Βɺ͜ΕʹҰ࣌తͳใΛ͍ΕΑ͏ʯ w ʁʁʮ͜ΕʯʁʁʮΑͧ͢͠ʯ w ࣮ɺηογϣϯͷण໋ཁ͍݅ ͜ͱ͕ଟ͍ w ʮʂʯͱ͔ݴΘΕΔ͜ͱ͋Δ
w ͠Βͨ͘͠ޙͰʮJEͬͯͳΜͷJE͔ͩΘ͔Βͳ͍͔ΒϦϑΝΫλ͠Α͏ʂʯ w ͢Δͱʜ -
Ωʔ໊มߋͳͲϚΠάϨʔγϣϯͭΒ͍ w ʮ$_SESSION['id']Λ['user_id']ʹ͠Α͏ʯ ʮίʔυΛॻ͖͑ͯσϓϩΠͩʂʯ PHP Warning: Undefined array key "user_id"
in ʙ w ʮΊͬͪΌΤϥʔग़Δʜͧʜʁʯ w ઌഐʮ͍͜͜͡Βͳ͍Ͱ͍ͩ͘͞ʯ ޙഐʮ͍ʯ -
݁Ռ w ʁʁʮҰମ͜ͷ$_SESSIONͲ͏͍͏ܗͳΜͩʜ ͜ͷ%50ࣺ͍͍ͯͯͷ͔ʜʁʯ w ఆٛͷͳ͍ྻத͕%50Ͱ͋ͬͯɺͱʹ͔͘Ϡό͍ w 1)1ͷηογϣϯશ෦ BUPNJDʹ ࠪมߋ
ϚΠάϨʔγϣϯ ͢Δ͜ͱ جຊతʹ Ͱ͖ͳ͍ ͓͡͞Μʹඞࡴཪٕ͋Δ w ͳͷͰϚΠάϨʔγϣϯ আ ͕Ͱ͖ͳ͍ w ઌഐʮ͜͜͞ΘΒͳ͍Ͱ͓͍͍ͯͩ͘͞ʯ ޙഐʮഐʯ -
ྫ 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); // औΓग़͠ -
session_start(); class A { public int $id = 1; }
$a = $_SESSION['a'] ?? new A(); $a->id = 123; $_SESSION['a'] = $a; -
"Λมߋͯ͠ΈΔ class A { public int $id = 1; }
↓ όʔδϣϯΞοϓͰϓϩύςΟ͕૿͑Δ class A { public int $id = 1; public int $name = 'taro'; } -
Ͳͤͳ͘ͳΔ 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ͷ༷Ͱ͜͏ͳ͍ͬͯΔ -
݁ՌɺΑ͋͘Δ෩ܠ w ʮ։ൃڥͰ͏͍ͨ͝ΜͰ͚͢ͲͶʯ w ʮΫοΩʔফͨ͠Β ࠶ϩάΠϯͨ͠Β Γ·͢ʂʯ w ·͋͜ΕखͰ͋Δ͕ʜ w
ˏͰѲΓͭͿͯ͠ɺ࠶࡞͢Δͷݟͨ͜ͱ͕͋Δ w ͔͜͠͠Ε'BUBMͩͧਖ਼ؾʹͳͬͯ΄͍͠ -
ϚΠάϨʔγϣϯΛͪΌΜͱॻͨ͘Ίʹ w ྻͷܗͰอଘ͓ͯ͘͠ w ͦΕΛຖճ%50ʹ࠶Ϛοϓ͢Δ w %50ʹόʔδϣϯ൪߸ΛຒΊࠐΜͰ͓͍ͯɺޓੑ͕ͳ͘ͳͬͨΒഁغ͢Δ w ͋Δ͍ϚΠάϨʔγϣϯ͢ΔΈ 5SBOTGPSNFS
Λ࡞Δ w ཁΒͳ͍σʔλ͕ফ͠ɺඞཁͳσʔλΛՃ w όʔδϣϯΛΈͯɺաڈͷϑΥʔϚοτ͔Βม -
͜͏ͳΔ ૿͑Δ͚ͩͳΒ 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(); // খωλ͕ͩɺ͜Ε͕ͳ͍ͱอଘ͞Εͳ͍͜ͱ͕͋Δ } } ͨͩ͠ɺ͜Ε͓͡ςΫͰ͢ਅࣅΔͳ -
ηογϣϯͷ%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, ) {} } -
// ͋Γ͏ΔΑ͏ͳɺηογϣϯͷܗঢ় $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' ]; -
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Ҿ͘ ]; } // ࣍ͷϖʔδʹͭͮ͘ -
ϧʔϓͯ͠ϚΠάϨʔγϣϯ͍ͯ͘͠ 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); } -
͕ΜͬͯΈ͕ͨʜ w ͗͜͢͠ΔʂͦͦյΕ͍͢ʂʂ w ʁʮΓͤΔͷʁʯࢲʮοʯ w ͜͏͍͏ͷɺ%#ʹߏԽͯ͠ೖΕͨ΄͏͕Α͍ ΩʔϢʔβʔ*%ηογϣϯ*%ͱͯ͠Ή w %#ͳΒී௨ͷ࡞๏ͰϚΠάϨʔγϣϯͰ͖·͢ΑͶʁ
w ͨͩɺηογϣϯ Ϣʔβ ͕ଟ͗͢Δͱେม͗͢Δͱ͍͏͜ͱ͋ΔΜ͢Α Ͷ w ʁʮΓ͞ΘΒͳ͍΄͏͕ฏͳͷͰʁʯ -
%#ͷετϥςδͷଞͷ͏Ε͍͠ w ϚϧνσόΠεαϙʔτෳσόΠεؒͰಉ͡σʔλΛར༻Մ $PPLJFͰͳ͘ɺϢʔβʔ*%Ͱఆ͢ΔͷͰ w ڧ੍ϩάΞτ%#ઃܭ࣍ୈͰɺಛఆϢʔβʔࢦఆͷڧ੍ϩάΞτ͕Մೳ w ʁʁʮී௨ͷ$_SESSIONͰͰ͖Δ͕ʁʯࢲʮͦΕଟ݁ہ%#Έͯ·͢Α Ͷʯ w
ී௨ͷ࡞Γͩͱɺڧ੍ϩάΞτͬͯ݁ߏ໘ͬ͢ΑͶ w ܽɺ%#আ͠ͳ͍ͱফ͑ͳ͍ࣄ ແݶʹଠΔɺҊ֎%&-&5&ॏ͍ -
·ͱΊ w $_SESSION1)1ͷศརηογϣϯػೳͰɺεςʔτཧʹ͑ͪΌ͏ w ʮεςʔτʯͷ࣮ํ๏৭ʑ͋Δ͕ͣͩɺ҆қʹྲྀΕ͕ͪ w ͱΓ͋͑ͣɺ։ൃͰ͖ͪΌ͏ɾۮવಈ͍ͪΌ͏ɻ w ण໋͕ܰࢹ͞Ε͕ͪɺΞϓϦέʔγϣϯͷण໋ΛͪΌΜͱߟ͑Α͏ w
ܕΛ͚Δ࣌ʹ͓͍ͯɺΓಈతͳྻ͚͍ͨ͞ΑͶʂ ิͰ͖Δ͠ w ޙ͔Βཧ͢ΔΑ͏ͳϚΠάϨʔγϣϯ૬͖ͼ͍͠ͷͰɺઌʹ͔Μ͕͑Α͏ -
session_start࣌ͷϑοΫ͕ͳ͍ w ͜Ε͕༗Δͱ݁ߏศརͩͬͨͷ͕ͩ ภͬͨײ w JOJͰઃఆ͍ͯ͠Δ߹ʹҧ͏͕ ɺTFTTJPO໌ࣔతʹ։࢝͢Δඞཁ͕͋Δͷ Ͱɺ ͦ͜Ͱ8SBQ͢Δͱྑ͍ ҟ͋Δ
w ͋Δ͍ɺauto_prepend_fileͰڧ੍తʹηογϣϯΛ։͚ͯɺ͍ͬͯ͡ɺ ด͡Δͱ͍͏ςΫ͋Δ -
Α͋͘Δແବ w ͱΓ͋͑ͣTUBSU͢ΔͷɺΞϯνύλʔϯ <?php session_start(); w ແବ͕Ϡό͍ɺ͋;ΕΔετϨʔδɺʮ1)1͕͍ʯͱ͍͏'6% w ΞΫηεͨ͠ॠؒɺϑΝΠϧ ηογϣϯ
࡞͞Εͯ͠·͏ w ʮ͔ͳΒͣTFTJTPO@TUBSU͢ΔϑϨʔϜϫʔΫ͕ѱ͍ʯ -
ΕΔηογϣϯ register_shutdown_function(function(){ if( session_status() === PHP_SESSION_ACTIVE && isset($_SESSION) && is_array($_SESSION)
&& count($_SESSION) === 0 ){ @session_destroy(); //ۭͷηογϣϯΛഁغ } }); register_shutdown_function4IVUEPXO࣌ʹݺΕΔϋϯυϥొ auto_prepend_fileͰ͍ΕΔ͜ͱͰ͖Δ ͜Ε͓͡ςΫͰ͢ɺਅࣅͳ͍Ͱ -
ͦͦͳΜͰ͜Μͳۤ͠Έ͕͋Δͷ͔ʁ w 1)1ͱ͍͏8"'ͷ4FTTJPOػೳΛཞ༻͍ͯ͠Δ͍ͤͰʁ w ཧղͯ͑͠ྑ͍ɺͪΌΜͱ͔͍ͭͬͯΕ࣮ࡍศར w ʮ΄͔ͷݴޠͰେৎʯ w ΄͔ͷ'8 ҉߸Խ$PPLJFʹೖΕͯΔ͚ͩͰͳ͍͔ʜʁ
1)1Ͱผʹ҉߸Խ$PPLJFͷϥΠϒϥϦ͋Δ w ʁʮ+XUͰղܾͰ͖Δɺۜͷؙʯ ʁʮʜͪΌΜͱ+XU࣮Ͱ͖͍ͯΔͳΒ͍͍Μ͡Όͳ͍Ͱ͔͢Ͷʯ