nanisore oishisou

Webエンジニアあるまさんのゆるふわ奮闘記。

Laravel5.6のセッション管理をmemcachedでやる手順(2)

パート1はこちらからどうぞ。

arm4.hatenablog.com

Laravelのsessionドライバーをmemcachedにしようと思ったわけだが
あんなにいつも親切なLaravelのドキュメントに、
なんと、設定方法が載っていなかった。

なので、Laravelのフレームワークのコードを読んで設定したぜよ

というお話。

Laravel 5.6 のsessionドライバーでmemcachedを使う(Macローカルで実験)

.envをのSESSION_DRIVERを書き換える。

.env

SESSION_DRIVER=memcached

vendor/laravel/framework/src/Illuminate/Session/SessionManager.php これによると、cacheドライバーとセッションドライバーの設定は共通らしい。

sessionのconfigのstoreにcacheのstoreのキーを指定すればよいっぽい。

    /**
     * Create an instance of the Memcached session driver.
     *
     * @return \Illuminate\Session\Store
     */
    protected function createMemcachedDriver()
    {
        return $this->createCacheBased('memcached');
    }
    /**
     * Create an instance of a cache driven driver.
     *
     * @param  string  $driver
     * @return \Illuminate\Session\Store
     */
    protected function createCacheBased($driver)
    {
        return $this->buildSession($this->createCacheHandler($driver));
    }
    /**
     * Create the cache based session handler instance.
     *
     * @param  string  $driver
     * @return \Illuminate\Session\CacheBasedSessionHandler
     */
    protected function createCacheHandler($driver)
    {
        $store = $this->app['config']->get('session.store') ?: $driver;

        return new CacheBasedSessionHandler(
            clone $this->app['cache']->store($store),
            $this->app['config']['session.lifetime']
        );
    }

config/session.php

    /*
    |--------------------------------------------------------------------------
    | Session Cache Store
    |--------------------------------------------------------------------------
    |
    | When using the "apc" or "memcached" session drivers, you may specify a
    | cache store that should be used for these sessions. This value must
    | correspond with one of the application's configured cache stores.
    |
    */

    'store' => 'memcached',

config/cache.php

    /*
    |--------------------------------------------------------------------------
    | Cache Stores
    |--------------------------------------------------------------------------
    |
    | Here you may define all of the cache "stores" for your application as
    | well as their drivers. You may even define multiple stores for the
    | same cache driver to group types of items stored in your caches.
    |
    */

    'stores' => [

        'apc' => [
            'driver' => 'apc',
        ],

        'array' => [
            'driver' => 'array',
        ],

        'database' => [
            'driver' => 'database',
            'table' => 'cache',
            'connection' => null,
        ],

        'file' => [
            'driver' => 'file',
            'path' => storage_path('framework/cache/data'),
        ],

        'memcached' => [
            'driver' => 'memcached',
            'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
            'sasl' => [
                env('MEMCACHED_USERNAME'),
                env('MEMCACHED_PASSWORD'),
            ],
            'options' => [
                // Memcached::OPT_CONNECT_TIMEOUT  => 2000,
            ],
            'servers' => [
                [
                    'host' => env('MEMCACHED_HOST', '127.0.0.1'),
                    'port' => env('MEMCACHED_PORT', 11211),
                    'weight' => 100,
                ],
            ],
        ],

        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
        ],

    ],

自分のMacmemcachedをインストールして実験するため
localhostなので設定はこのままで大丈夫そうだ。

しかしリロードするとMemcachedはないと怒られた。

Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR)
Class 'Memcached' not found

https://laravel.com/docs/5.6/cache#memcached-cache

cacheのほうのドキュメントを読んでみると、Memcached PECL package をインストールしなさいよと書いてある。

pecl install memcached

peclでインストールしてみたがエラーが出た。

ERROR: `/private/tmp/pear/temp/memcached/configure --with-php-config=/usr/local/opt/php/bin/php-config --with-libmemcached-dir=no' failed

libmemcachedのインストールでコケているっぽいのでbrewインストールする。

brew install libmemcached

再度、実行したらインストールに成功。

zlibでエラー出る人はXcodeのアップデートか、再インストールが必要そう。

pecl install memcached
.
.
Build process completed successfully
Installing '/usr/local/Cellar/php/7.2.6/pecl/20170718/memcached.so'
install ok: channel://pecl.php.net/memcached-3.0.4
Extension memcached enabled in php.ini

ちゃんと入っているので、phpをリスタートする。

php -i | grep memcached
memcached
memcached support => enabled
libmemcached version => 1.0.18
sudo brew services stop php
sudo brew services start php

保存されているかテストする

routes/web.php

Route::get('/', function () {
    session()->put('sample', 'beruko');

    return view('welcome');
});

ここでデバッグするためにddとか書いてしまうとsessionが保存されないので、デバッグしたい気持ちをぐっとこらえる。

telnetに接続しmemcachedに保存されているか確認する

stats items
STAT items:8:number 1
stats cachedump 8 1
ITEM beruko_sandbox_cache:uWTlfeZtpTUpHFAYfNR6nwycgA53gO0uZ1xg5nkp [273 b; 1529063998 s]
END
get beruko_sandbox_cache:uWTlfeZtpTUpHFAYfNR6nwycgA53gO0uZ1xg5nkp
VALUE beruko_sandbox_cache:uWTlfeZtpTUpHFAYfNR6nwycgA53gO0uZ1xg5nkp 0 273
a:5:{s:50:"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d";i:2;s:9:"_previous";a:1:{s:3:"url";s:26:"http://beruko-sandbox.test";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:6:"_token";s:40:"BVVBUIbJE94ZCLpb71aTLtSQzNI15r7MUIGwLdjj";s:6:"sample";s:6:"beruko";}
END

わーい♫ できたー

Laravel5.6のセッション管理をmemcachedでやる手順(1)

おっす、おらベル子。久しぶりのブログだぜっ!

最近、忙しくてイラストもまともに描けなくてストレスが溜まってるぜっ!
その代わり踊ってるんですが、踊りとイラストはまた別物なので、イラストを描く一人の時間がとにかく欲しいです。

昔から、好きなことに一人で没頭する時間がないと、快適に暮らしていてもストレスが徐々に溜まってきてしまうんですよね。

とにかく一人の時間を少し作って絵を描きたいです。

ということで本題です。

Laravel5.6のセッション管理をmemcachedでやりたい人向けの記事です。

memcached、何それ美味しいの?」な人から手順どおりやれば、Laravelのセッションドライバーをmemcachedでやれるようになります。

具体的にどういうときにmemcached使ったほうがいいのかというと、
Webサーバ2台構成とかでセッションを共有しないといけないなどの際に
ローカルストレージのfileじゃセッションの共有ができないので、 memcachedでやるとかそういう感じです。

キーと値のペアをメモリ上に保持するKVSの一種でRedisのお友達なので、
memcachedじゃなくてRedisでもいいです。

というかむしろ特別な理由がなければRedisでもいい気がしました。

まず、パート1ではmemcachedとは何かと基本的な使い方を学び、Macローカルにmemcachedをインストールします。

memcachedについて

gihyo.jp

memcachedとRedisの違い

yakst.com

qiita.com

post.simplie.jp

なるほどねー。

Macmemcachedをインストールし、実行確認する手順

memcachedbrewインストール

brew install memcached
which memcached

自動起動させるコマンドと、起動コマンドを案内してくれた。 brewでインストールしたので以下のフルパスじゃなくてmemcachedって打てば使えそう。

To have launchd start memcached now and restart at login:
  brew services start memcached
Or, if you don't want/need a background service you can just run:
  /usr/local/opt/memcached/bin/memcached

macOS High Sierratelnetを使えるようにする

https://qiita.com/samuraidays/items/b8a3d4a06e2c6c379865

brew install telnet

memcachedの起動オプション

オプション 説明
-p 利用するTCPのポート。デフォルトは11211
-m 最大のメモリーサイズ。デフォルトは64MB
-vv very verboseモードで起動してデバックメッセージやエラーをコンソールへ出力
-d memcachedをデーモンとしてバックグラウンドで起動
-h ヘルプを表示

telnet で接続

[~] telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.

バージョンの確認

version
VERSION 1.5.8

ステータスの確認

stats
STAT pid 3684
STAT uptime 96
STAT time 1529014973
STAT version 1.5.8
STAT libevent 2.1.8-stable
STAT pointer_size 64
STAT rusage_user 0.020749
STAT rusage_system 0.016610
STAT max_connections 1024
STAT curr_connections 2
STAT total_connections 3
STAT rejected_connections 0
STAT connection_structures 3
STAT reserved_fds 20
STAT cmd_get 0
STAT cmd_set 0
STAT cmd_flush 0
STAT cmd_touch 0
STAT get_hits 0
STAT get_misses 0
STAT get_expired 0
STAT get_flushed 0
STAT delete_misses 0
STAT delete_hits 0
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 16
STAT bytes_written 15
STAT limit_maxbytes 67108864
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT time_in_listen_disabled_us 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT slab_reassign_rescues 0
STAT slab_reassign_chunk_rescues 0
STAT slab_reassign_evictions_nomem 0
STAT slab_reassign_inline_reclaim 0
STAT slab_reassign_busy_items 0
STAT slab_reassign_busy_deletes 0
STAT slab_reassign_running 0
STAT slabs_moved 0
STAT lru_crawler_running 0
STAT lru_crawler_starts 510
STAT lru_maintainer_juggles 145
STAT malloc_fails 0
STAT log_worker_dropped 0
STAT log_worker_written 0
STAT log_watcher_skipped 0
STAT log_watcher_sent 0
STAT bytes 0
STAT curr_items 0
STAT total_items 0
STAT slab_global_page_pool 0
STAT expired_unfetched 0
STAT evicted_unfetched 0
STAT evicted_active 0
STAT evictions 0
STAT reclaimed 0
STAT crawler_reclaimed 0
STAT crawler_items_checked 0
STAT lrutail_reflocked 0
STAT moves_to_cold 0
STAT moves_to_warm 0
STAT moves_within_lru 0
STAT direct_reclaims 0
STAT lru_bumps_dropped 0
END

各項目の詳細

tetsuyai.hatenablog.com

データをセット&ゲット

このへんを参考にデータをセットしたりゲットしたりしてみる。

kakakakakku.hatenablog.com

morizyun.github.io

set

# set key flags expiretime bytes
set hoge 0 0 4
# value
huga
STORED

保存するbyte数が間違ってるとエラーが返ってくる

set hoge 0 0 4
laravel
CLIENT_ERROR bad data chunk
ERROR

get

get hoge
VALUE hoge 0 4
huga
END

ありもしないkeyを指定するとエラーは返ってこず、ただ終わる

get hogege
END

なるほど、難しいことは何もない。 Redisと変わらなそう。

インクリメントとかデクリメントとか、コマンド間違えてみたりとか

set count 0 0 1
1
STORED
get count
VALUE count 0 1
1
END
incr count 1
2
get count
VALUE count 0 1
2
END
decr count 1
1
get count
VALUE count 0 1
1
END
incr count 2
3
get count
VALUE count 0 1
3
END

ありもしないキーを指定

decr count3
ERROR

存在しないコマンドを唱える

dect count 3
ERROR

なるほど、Redisと一緒ですね。

保存しているキーの一覧を表示

stats itemsと打って、items:{m}:number {n}みたいな行を探し、 stats cachedump {m} {n}みたいに打つと、キーの一覧を表示できる。

stats items
STAT items:1:number 2
STAT items:1:number_hot 0
STAT items:1:number_warm 0
STAT items:1:number_cold 2
STAT items:1:age_hot 0
STAT items:1:age_warm 0
STAT items:1:age 572
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 0
STAT items:1:expired_unfetched 0
STAT items:1:evicted_unfetched 0
STAT items:1:evicted_active 0
STAT items:1:crawler_reclaimed 0
STAT items:1:crawler_items_checked 6
STAT items:1:lrutail_reflocked 0
STAT items:1:moves_to_cold 7
STAT items:1:moves_to_warm 5
STAT items:1:moves_within_lru 0
STAT items:1:direct_reclaims 0
STAT items:1:hits_to_hot 0
STAT items:1:hits_to_warm 0
STAT items:1:hits_to_cold 7
STAT items:1:hits_to_temp 0
END
stats cachedump 1 2
ITEM count [1 b; 0 s]
ITEM hoge [4 b; 0 s]
END

mitsuakikawamorita.com

キーの削除

delete hoge
DELETED
stats items
STAT items:1:number 1
.
.
END
stats cachedump 1 1
ITEM count [1 b; 0 s]
END

有効期限付きでセット

set some_id 0 10 1
1
STORED

速攻唱えると参照できるが

get some_id
VALUE some_id 0 1
1
END

10秒後に唱えると消えている。

get some_id
END

儚い。

telnetを終了する

^C^]
telnet>  q
Connection closed.

memcachedコマンド一覧

l-w-i.net

NoSQL比較

qiita.com

Redisと違って、永続化もできないし、保存できるデータ構造も文字列しかなさそうなので
他にいろんな用途で使うようなことがあればRedisのほうがいいのかなと思いました。
でもmemcachedはシンプルで分かりやすくていいです。

ちなみにLaravelのセッションドライバーはRedisも選べます。

パート2はLaravel側の設定について書くぜ!
お楽しみにー。

Vuex使った時にフォームのバインディングにv-model使うと怒られる問題の解決法

Vuex使った時にフォームのバインディングにv-model使うと怒られる問題の 最終的な私の答え。

eventでvalueとキーネームを飛ばして ミューテーションでキーネーム付け合わせて、 バーンて入れるだけ。

これならミューテーションにupdateHogeを入力項目ごとに書かなくて済む。

inputにはこれを書いて

:value="blogForm.title"
@input="updateBlogForm($event, 'title')"

inputのあるコンポーネントのmethodにはこれを書いて

updateBlogForm(e, key_name) {
    this.$store.commit('updateBlogFormValue', { value:e.target.value, key_name });
}

ストアにこれを書くだけ

updateBlogFormValue (state, { value, key_name }) {
    state.blogForm[key_name] = value;
},

思いついたときに感動した。


【キーワード】 Vuex form input v-model エラー mutation バインディングイデア

Laravel mixでbrowserSyncを使っている場合に<pre>タグを使うと、その前に謎の<script>が入りVueコンパイルエラーになるぞ

ググってきた人のために最初に言っておく、 この問題の解決策は見つからなかったので、ここには解決策は書いてない。

解決策を求めている人は、今すぐ立ち去るが良い。

Laravel mixでbrowserSyncを使ってブラウザの自動リロードをしている場合に、
ドキュメントに

<pre>

preタグがあると、閉じタグの前に謎の

<script>

scriptタグが挿入され
Vue.jsのテンプレートコンパイルエラーが出て怒られる。

Error compiling template

対処法は今のところ見つかっていないが、自動リロードしているタブじゃなければエラーは発生しないので
本番&ステージング環境などでは特に問題はなさそう。

ちなみにpreタグのある箇所の親divにv-preをつけてもエラーは消えない。

【キーワード】 Vue.js vue コンパイルエラー Error compiling template Laravel mix browserSync BrowserSync browser sync preタグ

$requestでは$request->get()はダメ、ゼッタイ

Laravel4に慣れてる諸君は分かると思うが、Laravel4ではInput::get()という書き方をしていたので
Laravel5系でもついつい$request->get()って書いてしまう。

さらに悪い事に$request->get()と書いても入力値が取得できてしまう。
でもこの$request->get()で取ってくる値は、Symfonyのほうのメソッドなので
単に入力値を取ってくるだけのやつなのである。
よって、FormRequestでごちゃごちゃやってるのは何も反映されない。

なので、必ず入力値は$request->input()で取得するように。
お姉さんとの約束だ。

$request->input()

safariで出力ファイルの拡張子に.htmlを付けられる時の対処法

対処方法1

出力処理の最後にexit;を足す。 ※ ただし、exitで処理をぶった切るので、middlewareでactionのafterにごちゃごちゃやってると、それもぶった切られる。

        // ファイル出力
        $fp = fopen('php://output', 'w+b');
        fwrite($fp, $csv);
        fclose($fp);
        exit;

【参考】 https://stackoverflow.com/questions/19363744/safari-adding-html-to-download

https://qiita.com/mata/items/6a30b65ecc71e02d447a

対処方法2

responseヘルパーを使ってレスポンスを返す

ex) csv

        $csv = FileUtils::createCsv($user_rows);
        
        return response($csv)->
            header('Content-Type', 'text/csv')->
            header(
                'Content-Disposition',
                'attachment; filename="'.$file_name.'.csv'.'"'
            );

ex) zip

        $headers = [
            'Content-Type' => 'application/zip',
            'Content-disposition' => 'attachment; filename*=UTF-8\'\''.rawurlencode($zipName),
            'Content-Length' => filesize($zipPath)
        ];

        return response()->download($zipPath, $zipName, $headers);

【キーワード】 safari Safari 出力 csv zip 出力 拡張子

youtubeのソースに埋め込まれてるogpタグを確認する方法

youtubeの仕様が変わって、UserAgentを見てogpタグの出力を制御している模様。

Google dev toolでカスタムUserAgentに以下を指定することで、ogpタグを確認することができる。

facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)

f:id:arm4:20180319183701p:plain

参考

stackoverflow.com

Google ChromeでカスタムUserAgentを指定する方法はこちら

qiita.com

ogpタグ値をChrome拡張機能で確認

ogpタグで指定されている値をさくっと確認したい場合は、こちらのChrome拡張入れると便利。

Open Graph Preview

chrome.google.com

こんな感じ。

f:id:arm4:20180319183610p:plain