SHIRANGANA 忍者ブログ
エンジニア日記
Admin / Write
当ブログは下記に移転します。

MUGIJIRU.JP
PR
図にまとめたので上げておきます。
要点は

・laravelのセッションはネイティブPHPのセッションを使っていない。
・cookieに設定される値は暗号化される。
・cookieに保存されるセッションid(laravel_session)とトークン(XSRF-TOKEN)はcookie名が違う。
・tokenはセッション作成時に発行され、regenerateしない限り不動。
・tokenをリクエストする方法は3通り(ヘッダ2パターン、パラメータ1パターン)ある。

というところあたりだと思います。

意外な落とし穴では

・cookieの暗号化はenvのAPP_KEYがsaltに使われているので変更すると複合できなくなる
・URL毎にlaravel_sessionにあたるcookie名を分けている場合、XSRF-TOKENも揃えないと意味がない
 (x-csrf-token, _tokenだけで制御されているなら不要ですが)
XSRF-TOKENのcookieの有効期限がなぜかソースに直書きになっているので
 期限を伸ばすならばオーバーライドが必要
    https://teratail.com/questions/27003

という点が挙げられます。

CSRF TOKENと関わりの深い話題だと思うので[こちら]もどうぞ。

「せや!セッション持続時間を永続化したろ!」
「expire_on_close = true!これで放置しても大丈夫やで!」
 
〜約2時間後〜
 
SE「消えたンゴ」
PG「ワイは消えてない・・・なぜなのか」
 
という状況の解決策をシェアしたいと思います。
 

解決策:

lifetimeを長めに取ってみて下さい。
gc(ガベージコレクション)がセッションデータを削除しているかもしれません。

expire_on_closeがtrueならlifetimeは無視されると思いきや・・・ 

実はガベージコレクションの判定では使用されています。

LaravelもネイティブPHPも、セッションデータを失う条件は
 
1.cookieが削除された
2.セッション自体の有効期限が切れた
3.gcが発動した
 
の3通りが主で、Laravelの場合1と2はexpire_on_closeで対応できますが
3はlifetime + lotteryの設定で動作するようになっています。
 
要するに、expire_on_closeがtrueでセッション自体の有効期限を永続化しても
ガベージコレクションが起こればデータが削除される場合があるということです。
 
例えば、lifetimeが120、lotteryが[2, 100]であるならば
そのサーバに誰かからアクセスされる度、
2/100(=2%)の確率で2時間以上更新されていないセッションデータを削除するという動きをします。
(消えたり消えなかったりのムラはこの確率判定が原因です)
 
極端な話、lifetime = 1 / lottery = [100, 100]にすると、
expire_on_close = trueでも
1分以内にアクセスしなければセッションが吹っ飛ぶ様を見ることができます。
 
放置されがちなアプリなら2時間は短いと思うので、例えば
「1週間触られていないセッションデータはさすがにゴミデータですよね」というポリシーなら
lifetimeは 60分 x 24時間 x 7日 = 10080
等と設定すれば良いと思います。
 
gcを緩めすぎてデータ量が肥大化しないよう、
アプリの用途と規模を考慮し、用法用量を考えて正しくご設定くださいませ。
 
 
最近から、ChromeにおいてjQueryでformをsubmit処理をするとき
Form submission canceled because the form is not connected
というメッセージがコンソールに出るようになり、submitができなくなることがあります。
 
これはChromeのバージョン55系までは出ておらず、56系から出るようになりました。
(発生した私の環境では56.0.2924.87 64-bitでした)
 
このエラーは、ブラウザが描画しているdocumentに埋め込まれていないformを
submitしようとするときに発生します。
 
端的に言うと下記のような感じ
$('<form action="hoge"></form>').submit(); // これは上記のメッセージが出る。
 
暫定の対応としては、
form要素をdocumentに一度埋め込むことによって動作するようになります。
 
たとえば
 
var form = $('<form action="hoge"></form>');
var temp_wrapper = $('div#temp');
 
temp_wrapper.empty().append(form);
form.submit(); // 正常にsubmitされる。
 
みたいな感じ。
 
理由は、HTMLの仕様がそうであるからでした。
 
上項の2番に書いてあるとおりで、documentに結合していない要素の処理は無視されます。
chromeはver56系からこれに従ったため、メッセージが出るようになったと思われます。
 
以前から、このテクニックは裏技っぽい使い方だな、と思っていましたが、
実際にブラウザハックだったということになりますね!
正式な仕様としてはNGということになります。
 
普段何気なく使っているHTMLですが、
不具合を出してお客さんに迷惑をかけたり、恥ずかしい思いをしないためにも
一度くらいは通しで規約を読んだほうが良さそうですね。
 
参考URL

いつもお世話になっているHtml, Formの生成ヘルパーである LaravelCollective/Html
Laravelのコアから外れた今でも、その利便性が褪せることはありません。

しかしながら、その機能の中で、今までどうしても不満に思っていた点がありました。
それは、Form Model Bindingをする時に
日付がCarbonである場合、テキスト出力される際にフォーマットが指定できず、
テキスト欄に強制的にY-m-d H:i:sと出てきてしまっていた点です。

なぜここだけこんなにも融通が利かないんだろう。
という印象を受けた人は一人ではないのではないかと思います。

私も、dateと datetimeメソッドをフォーマット指定が可能なように
拡張したクラスを作成しようか何度も迷っていました。

最近もまた、そんなことを考えていたところ!

Ver5.2から新機能が追加されてた。
FormModelBinding専用のアクセサが実装できるようです。

このように書くことができるようになります。(公式より抜粋)
https://laravelcollective.com/docs/5.2/html#form-model-accessors

namespace App;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Get the user's first name.
     *
     * @param  string  $value
     * @return string
     */
    public function getDateOfBirthAttribute($value)
    {
        return Carbon::parse($value)--->format('m/d/Y');
    }

    /**
     * Get the user's first name for forms.
     *
     * @param  string  $value
     * @return string
     */
    public function formDateOfBirthAttribute($value)
    {
        return Carbon::parse($value)->format('Y-m-d');
    }
}

formDateOfBirthAttribute が専用アクセサですね。
(getDateOfBirthAttributeはもともとあるEloquentのアクセサです)

まだ自由自在になりきったというところまではいかないものの、
普段使いで露骨に不足しない程度にはなってきたのではないかと思います。

ありがたいことです。

1  2 

忍者ブログ [PR]