Web storageのlocalStorageの実体を調べる
WebAudioを使ったスクリプトを書いていたのですが、パラメータを保存したいと思いました。で、HTML5と共にlocalStorage(を含むWeb storage)が実装されていたような気がしたので、使ってみることにしました。
ところで、世の中的にはどんな用途でlocalStorageを使っているのか、自分のPCに格納されているlocalStorageの実体を調べてみました。
Web storageとは
Web storageには永続的なlocalStorageと、セッション内でのみ有効なsessionStorageの2種類あります。一般的なcookieと異なり、localStorageを使えば永続的にデータを保持することが可能になります。
そういえば、冒頭にも書いたようにHTML5の一部だと思っていたのですが、米Wikipediaによれば現在ではHTML5とは切り離された仕様として定義されているようです。
Web storage is being standardized by the World Wide Web Consortium (W3C). It was originally part of the HTML5 specification, but is now in a separate specification.
Web storage - Wikipedia
Web Storage (Second Edition)
永続的にデータを保持されるということは、消さない限り消えないわけです。たとえ一定期間経過後に削除するようなコードが実装されていても、そのサイトをユーザが再度訪れない限りは削除ロジックは発動しません。この特性を考慮すると、開発者にとっては便利に使えても、ユーザにとってはゴミデータを貯え続けられてしまう可能性もあるわけです。
そこで、PCのどこにどのくらいlocalStorageによってデータが格納されているか調べてみました。
格納場所
Windows版Google Chromeを使用していると、以下のディレクトリにlocalStorageの実体が保持されているようです。
%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default\Local Storage\
このディレクトリ内を見てみると、以下のようになっていました。
>dir ドライブ C のボリューム ラベルは VOLUME_LABEL です ボリューム シリアル番号は XXXX-XXXX です C:\Users\USERNAME\AppData\Local\Google\Chrome\User Data\Default\Local Storage のディレクトリ 2017/02/21 02:28 <DIR> . 2017/02/21 02:28 <DIR> .. 2017/02/20 01:05 10,240 chrome-devtools_devtools_0.localstorage 2017/02/20 01:05 0 chrome-devtools_devtools_0.localstorage-journal …中略… 2628 個のファイル 59,284,016 バイト 2 個のディレクトリ 808,513,536 バイトの空き領域
サイトやChromeアプリ毎に.localstorageというファイルと.localstorage-journalというファイルのペアが作成されているようです。
また、私のPCでは合計60MB弱になるようです。大した量ではありませんが、増設も換装も不可能な特殊形状のUltrabookのSSDを無意味なデータに占有されるのは嬉しくありません。
永続的ということで、消えずに残っているゴミのようなlocalStorageを探してみることにします。私のPCで最も古いlocalStorageのファイルを3組例示すると、下のようなタイムスタンプで2年以上前。たぶん、このPCを使い始めたころだと思います。
2014/12/10 14:46 3,072 https_getadblock.com_0.localstorage 2014/12/10 14:46 3,608 https_getadblock.com_0.localstorage-journal 2014/12/17 17:14 3,072 https_account.asus.com_0.localstorage 2014/12/17 17:14 512 https_account.asus.com_0.localstorage-journal 2014/12/17 17:15 3,072 https_vip.asus.com_0.localstorage 2014/12/17 17:15 512 https_vip.asus.com_0.localstorage-journal
上記のように3KB程度なら、放置しててもいいかと思えなくもありません。次に、古さではなく大きさでソートしてみると、上位10ファイルは以下の通り。
2016/06/09 18:56 8,224,768 chrome-extension_gighmmpiobklfepjocnamgkkbiglidom_0.localstorage 2017/02/20 22:59 5,734,400 https_ja.wikipedia.org_0.localstorage 2017/02/20 23:54 4,620,288 chrome-extension_nafpfdcmppffipmhcpkbplhkoiekndck_0.localstorage 2016/03/27 18:30 2,923,520 http_www.higuchi.com_0.localstorage 2017/02/21 02:17 2,555,904 https_en.wikipedia.org_0.localstorage 2017/02/12 18:14 1,933,312 https_www.wsj.com_0.localstorage 2017/02/12 18:11 1,769,472 https_commons.wikimedia.org_0.localstorage 2016/10/31 04:00 1,667,072 http_www.tp-link.jp_0.localstorage 2016/06/09 20:19 1,532,928 http_www.thevegashookup.com_0.localstorage 2016/01/18 12:08 1,222,656 https_zh.wikipedia.org_0.localstorage
chrome-extensionから始まる、Chromeのプラグインが使用しているファイルや、各国のwikipediaによって保持されたファイルが大きいようです。
ところでこれらは具体的に一体どのようなデータを保持しているのでしょうか。私はWikipediaは参照するだけで編集したこともないですし、中身が気になるので見てみることにします。
.localstorageを開く
バイナリエディタで開いてみると、"SQLite format 3"という文字列から始まっていることが判ります。ということで、これはSQLiteのデータファイルのようです。
SQLite公式から"A bundle of command-line tools for managing SQLite database files, including the command-line shell program, the sqldiff.exe program, and the sqlite3_analyzer.exe program."をダウンロードします。
SQLite Download Page
展開したファイル中の"sqlite3.exe"がSQLiteのコマンドラインクライアント(Oracleで言うところのSQL*Plus)なので、これを使うことで内部のデータにアクセスできます。
sqlite3で.localstorageにアクセス
sqlite3を起動すると以下のようなバナー表示に続いて、SQLiteのプロンプト表示となります。
SQLite version 3.17.0 2017-02-13 16:02:40 Enter ".help" for usage hints. Connected to a transient in-memory database. Use ".open FILENAME" to reopen on a persistent database. sqlite>
.openコマンドでデータファイルを開きます。この際ディレクトリ指定の\マークは\\とする必要があります(\で指定してもエラーメッセージは表示されませんが、意図したファイルも開かれません)。
sqlite> .open "C:\\Users\\USERNAME\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Local Storage\\chrome-extension_gighmmpiobklfepjocnamgkkbiglidom_0.localstorage"
データファイルが開けても、内部のテーブル名が判らなければSQLを叩けません。Oracleで言うところのDBA_TABLES等のディクショナリやQL*Plusで言うところの"show tables"コマンドに相当するコマンドが、SQLiteでは".table"になるようです。
sqlite> .table ItemTable
テーブル名がItemTableだと判ったので、とりあえず参照してみます。
sqlite> select * from ItemTable; …結果略…
ごっそりとコンソールに出力が流れました。そりゃそうですね、8MB以上もあるデータファイルで単一テーブルなのだから、何も考えずに全件表示したらこうなります。
ということで、SQL*Plusで言うところの"spool"コマンドに相当するのが、SQLiteでは".out"になるようです。
sqlite> .out out.txt sqlite> select * from ItemTable; sqlite> .out stdout
これでselect結果をout.txtに落とし込めました。
具体的なデータ内容はここには掲載しませんが、所謂Adblockプラグインのブロック対象リストがデータ量の9割以上を占めていました。過去にAdblock系のプラグインを使用していたことがありますが、1年以上前にアンインストールしています。それでもlocalstorageは消えずに残っていることになります。
ついでに、このItemTableのテーブル構造を知りたいと思いましたが、SQL*Plusで言うところの"desc"コマンドに相当するものは見当たらないので、スキーマ内オブジェクトのDDLを表示する".schema"を叩いてみます。
sqlite> .schema CREATE TABLE ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value BLOB NOT NULL ON CONFLICT FAIL);
ということで、ItemTableはkey, valueの2カラムからなるテーブルのようです。で、keyは文字列でユニーク、valueはBLOBでNULL不可と。
これがそのままlocalStorageのkey, valueのペアに相当しているようですね。
データ構造が判ったので、他の巨大なファイルも同様に内部を確認してみました。
WikipediaのlocalStorageには巨大なJavaScriptが保持されていたり、TP-LINKのlocalStorageにはWOFF形式のWeb Fontがbase64エンコードされた文字列が格納されていたり、ExifViewerプラグインのlocalStorageには最近表示された画像のURLとそのEXIFデータのJSON文字列がキャッシュとして保持されていたり、それぞれのデカさに相当するデータが保持されていました。
それって、単なるブラウザキャッシュじゃダメなのかとか、sessionStorageではなくlocalStorageとして永続的に保持する必要があるのか等、疑問に感じる使われ方も多く見当たりました。
以上。