hkのweblog

ひよっこエンジニアがにわとりになるまでの軌跡

Cookieに複数の値を格納したい時に

1つのCookieに複数の値を入れたい、配列を入れたい、そんな時に使える便利な方法をメモしておきます。

こいつを使います↓
https://github.com/carhartl/jquery-cookie

基本的な使い方

例えば、連想配列Cookieに格納する場合を想定してみます。

//以下でCookieをjson化する
$.cookie.json = true;

//sampleHashという連想配列をsample_cookieというCookieにjson形式で保存する
let sampleHash = {fruit: 'apple', vegetable: 'tomato'};
$.cookie('sample_cookie', sampleHash);

//json形式で保存された'sample_cookie'をパースして連想配列に戻す
let parsedHash = $.cookie('sample_cookie');
console.log(parsedHash.fruit);
// apple

実にシンプルです。
1つのサイトで持てるCookieの数には上限があるので、使い所はあるのかなと思います。
その一方で1つのCookieの容量は4096byteが上限となっているので、いたずらにCookieを膨らませていくとオーバーしてしまうので注意が必要です。
短いですが今日はこんなところで。

awkコマンドを使ってログを調べる

先日、自分のリリースしたものが派手に障害を起こしてしまい、影響範囲を調べるためにエラーログをあれこれいじる機会がありました。
こういう機会は無いに越したことはないのですが、その時に活躍したawkコマンドについて簡単にまとめておきます。

awkとは

awkは厳密にはコマンドではなく、それ自体がスクリプト言語のようです。単一のテキスト(ファイル)を整形したりするのに便利なツールです。
シェルスクリプトといえばPerlが思い浮かびますが、そこまでの学習コストを必要とせず、簡単にフィルタリング処理を書けるのがawkの特長です。


基本的な使い方

例えば以下のようなテキストファイルがあるとします。
sample1.txt

hoge fuga foo bar

とりあえず、sample.txtからfugaを取り出してみます。

awk '{print $2}' sample1.txt
// fuga

このコマンドでスペース区切りの2番目の要素を取り出すことができます。
他にも色々できます。例えば正規表現を使ってみます。
まずこんなテキストファイルがあるとします。
sample2.txt

hoge fuga
hello world
test dayo

この中からhが含まれる行だけを取り出してみます。

awk 'match($0, /h.*/)' sample2.txt
// hoge fuga
   hello world

第1引数に$0を指定していますが、これで全要素を指定することができます。
第2引数は見ての通りhから始まる要素を取り出す正規表現です(hは途中でもOKです)。
awkの使い方は他にも色々あるのですが、キリがないのでこの記事では割愛します。


ログから会員番号を抽出してみる

どのようなデータをログに残しているかはシステムやサービスによって当然異なるとは思うのですが、ログをちょっと眺めてawkコマンドを活用すれば、膨大なログの中から必要な情報を抜き出すことができます。
自分の場合、障害にかかって画面を表示できなかったサイト会員がどれくらいいるのか調べる必要がありました。
出力されていたエラーログは大体こんな感じでした。 sample_error.log

ERROR~~~~~~(中略) /error/no/genninn.jspが存在しません。 ~~~(中略)~~~memberCode=213122~~~(中略)

だいぶ端折ってしまいましたが、こんなログ大量に出力されていました。
この中には今回の障害には関係ないものも含まれているので、今回の障害に関連したものだけを抽出してみます。

grep ERROR sample_error.log | grep genninn.jsp | awk '{print $15}' | sort | uniq
///memberCode=111112
   memberCode=111133...

awkも他のコマンド同様、パイプで繋いで使うことができます。
まず最初にgrepコマンドで対象ファイルの中で「ERROR」を含む行を取得。さらに対象ファイルの名前を含む行を抽出します。ここでようやくawkが登場。各行の中からmemberCodeを含む要素を抽出しています(memberCodeはスペース区切りで15番目でした)。
sortは文字通りのソート、繰り返しエラーにはまっている会員の重複を排除するのにuniqを使っています。
当時の稼働系サーバーは一桁の台数だったので、各サーバーに入って同じコマンドを叩き、出てきたものをsort|uniqしてまとめました。
ここでさらにawkを活用してやれば「memberCode=」の部分を削るなんてこともできそうですね。
結果…
実に100以上の会員がgenninn.jspを表示できずに困っていたことが判明しました。
我ながら本当に酷いですね…
悔い改めつつ今日はこんなところで。

Vagrant上にLaravelの開発環境を作る

2年以上前にフレームワークを使わずにPHPで書いたサイトがあるのですが、久しぶりにAnalyticsを見たらまだ日に30PVくらいのアクセスがありました。
今ならもっと良いサイトにできそうな気がしたので大規模改修をしようと思い立ち、Laravelベースで再実装することにしました。
というわけで早速Laravelの開発環境を作ったので、経過をまとめておきます。

最初にやっておくこと

Homesteadのvagrant boxを追加

そもそもHomesteadとは

ざっくり言えば、Laravelの開発環境をまとめたBoxです。 Homesteadの公式サイトによれば、

Homesteadは、WindowsMacLinuxシステムで実行でき、Nginx Webサーバー、PHP7.0、MySQL、Postgres、Redis、Memcached、Nodeやその他、素晴らしいLaravelアプリケーションを開発するために必要な、クールなツールを全部含んでいます。

だそうです。
これさえ入れておけば大体は事足りそうです。

VagrantにHomesteadを入れる

vagrant box add laravel/homestead

途中でどの環境に入れるのか聞かれるので、virtualboxを選択します。そこそこ時間がかかります。

Homesteadのダウンロード&初期化

任意のフォルダに移動し、git cloneします。

git clone https://github.com/laravel/homestead.git Homestead

git cloneしたら新しくできたディレクトリ(Homestead)に入って、以下のコマンドをたたきます。

bash init.sh

これでHomestead内にHomestead.yamlという設定ファイルができるはずです。

設定ファイルの書き換え

Homestead.yamlの書き換え

先ほどできたHomestead.yamlを書き換えます。最初は以下のような状態のはずです(バージョン次第で違うかも)

---
ip: "192.168.10.10"
memory: 2048
cpus: 1
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: ~/code
      to: /home/vagrant/code

sites:
    - map: homestead.app
      to: /home/vagrant/code/public

databases:
    - homestead

# blackfire:
#     - id: foo
#       token: bar
#       client-id: foo
#       client-token: bar

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp

このうち、書き換えるべきはfoldersとsitesの2項目です。SSHキーを作る場合も変更が必要ですがこの記事では割愛します。

foldersはvagrant上のディレクトリにローカルディレクトリをマウントする設定です。書き換え方は以下のような感じ。

folders:
    - map: ~/[ローカルでプロジェクトを作る場所]/[これから作るプロジェクト名]
      to: /home/vagrant/code

次にsitesです。こちらはサイトとして公開するディレクトリの設定です。

sites:
    - map: homestead.app
      to: /home/vagrant/code/[これから作るプロジェクト名]/public

mapのところは任意のものに変えても大丈夫みたいです。

hostsの書き換え

macの場合、/etc/hostsを書き換えます。windowsでは場所が違うみたいです。
自分の場合、ルート権限が必要だったのでsudo vi hostsで書き換えました。

192.168.10.10   homestead.app

先ほどHomestead.yamlに設定したmapと連動するので、IPと名前は合わせておきます。

vagrantの起動とプロジェクト作成

vagrantの起動

先ほどHomesteadをgit cloneしたディレクトリに移動してvagrant upします。
ちゃんと起動すればvagrant sshvagrant環境に入れます。

プロジェクト作成

vagrant環境に入ったらcodeディレクトリに移動し、以下のコマンドでLaravelのプロジェクトを作成します。
Composerを使うんですね。

composer create-project laravel/laravel --prefer-dist [任意のプロジェクト名]

--prefer-distは安定版を入れるというオプションだとか。(Composerの使い方よく知らない…)

Laravelが導入できたか確認する

方法は簡単です。vagrantを起動した状態でHomestead.appにアクセスして、こんな画面が表示されれば成功です。 f:id:h2r4t:20170923233312p:plain なお、うまくいっていない時は「no input file specified」と表示されます。
おそらくHomestead.yamlかhostsの設定の問題なので、このあたりをよく確認しましょう。
おつかれさまでした。
さてさて、Laravelは素人ですが、これからいい感じのサイトを作れたらいいなあ。

【無料】Kindleストアで見つけたAngular4のおすすめ書籍

今日は最近Kindleで見つけたAngular4のおすすめ書籍を紹介しようと思います。しかも無料…!

Kindleストアでは技術系でも無料の書籍を時々見かけます。ただ、買ってはみたもののクオリティはお察し…というのがいつものパターン。
と、私も思っていたのですが、今回、無料とは思えない良書を見つけました。
それがこちら↓

英語の本ではあるのですが、エンジニアたるもの少々の英語は読めたほうがいいですよね。
今のところ日本人によるレビューは一つもついていないのですが、Amazon.comのレビューは29件で平均4.5くらい。
分量も十分です。この本、普通に数千円で売っていいレベルだと思います。

この本はAngular4の技術書で、簡単なものから始まって少しずつAngularでアプリケーションを作っていく流れになります。 Angularといえば、2系からはTypeScriptについての理解も必要となり、構造そのものを理解するにも苦労するイメージがありました。
ただ、この本はZone.jsなどのモジュールがどのようにアプリケーションを動かしているのか、コンパイルとトランスパイルの違いまで説明があり、かなり分かりやすく納得感がある印象でした。

また、特徴的なところとして、Plunker上で開発を進めている点が挙げられます。
Plunkerは、ブラウザ上でコードを書いて実行できるツールで、コードを共有することもできます。あまり馴染みのない人も多いかもしれません。

Plunkerを使えば、面倒な開発環境構築が必要なく、お手軽にAngularの開発を楽しむことができます(とはいえブラウザ上では限界があるので本格的にやるなら自前で環境を用意したほうがいいとは思います)。
この本では、段階ごとにサンプルコードがPlunkerで共有されており、確認することができます。
ですので、ブラウザを開きながら、PC版のKindleで読むのがおすすめですね。

実はかく言う私もまだ10%くらいしか読めていないので()、これからどんどん読み進めていきたいところです。

Docker上にrails環境を作ろうとして苦労した話

先日、Docker上にrailsの開発環境を作ったのですが、やたら苦労して丸一日を費やしてしまいました。ということで簡単に手順をまとめておきます。

Dockerfileを作るまで

  • Dockerのインストール
    まず、Dockerをインストールします。今回はWindows10にインストールしました。こちらの公式サイト「Get Docker for Windows[stable]」からインストーラーをDLしてそれに沿って進めました。簡単ですね。

  • Dockerfileを書く
    今回ベースとなるDockerイメージはCentOS6.5にしました。rubyのバージョンは2.3.3です。 ここに必要なものを入れていくためのDockerfileを書きます。今回はDockerfileが社内に用意されていたのですが、こいつがあちこちひっかかり、丸一日苦しむことになりました。。
    以下にDockerfileの一部を書いておきます。長いのでだいぶ端折ってます。

FROM hasedon/centos6.5.1:latest

#色々インストール
RUN yum install -y tar
RUN yum install -y openssl-devel readline-devel zlib-devel
RUN yum install -y git
# 中略

# rubyインストール
RUN git clone git://github.com/rbenv/rbenv.git /usr/local/rbenv
RUN git clone git://github.com/rbenv/ruby-build.git /usr/local/rbenv/plugins/ruby-build
ENV PATH=$PATH:~/.rbenv/bin:~/.rbenv/shims
RUN rbenv install 2.3.3
RUN rbenv rehash
RUN rbenv install global 2.3.3
RUN gem update --system
RUN gem install --no-ru --nordoc rails
RUN gem install bundler
RUN rbenv rehash

コンテナを実行する

  • docker buildする
    先に書いたDockerfileを任意の場所に配置し、コマンドラインツールでDockerfileのある場所に移動、以下のコマンドを実行します。 こんな感じでユーザー名も設定することも可能です。(不要の場合は–build-arg name=[user name]を削ればOK)
docker build --build-arg name=[user name] ./

ここで docker image を実行すると、今buildしたイメージを確認できます。

が!自分の場合、RUN rbenv install 2.3.3のところでこけました…
色々調べたところ、インストールの際にcurlが走るようなのですが、こいつのバージョンが古すぎてダウンロードに失敗するようです。ググってみると同じ問題に直面している方を何人か見つけました。
Dockerfileの途中にRUN curl --versionと書いてビルドするとcurlのバージョンが表示されます。自分の場合は7.19.4でした。2017年8月時点で7.55.1が最新版です。

仕方ないので DockerfileのRUN rbenv install 2.3.3以下こけてしまう行はコメントアウトしてビルドし、問題を先送りします()。これでとりあえずは新しいイメージができます。

  • docker runする
    まず、 docker ps を実行すると、実行中のコンテナが表示されます。現時点で何も動いていないことが確認できるはず。 次に
docker run -v [ホストディレクトリのパス]:[コンテナのパス] [イメージ名] /bin/bash

ここでコンテナIDが返されると実行できているはずです。上記のようにマウントしなくても良いのですが、マウントしておくと後々windows上から触れるので便利です。
当然何らかのエラーを返す場合もあるようです。自分の場合はエラーは返さないけど、入力待ちにもならず…みたいな状態になりました。
原因究明に半日費やしましたが、ヤケクソでwindowsごと再起動したらうまくいくようになりました。Dockerそのものがうまく動いてなかったのか何なのか。

rubyを入れるまで

  • curlのバージョンをあげる
    先ほど後回しにした問題を解決すべく、まずは実行中のコンテナに入ります。 docker -it exec [コンテナID] /bin/bashで入れます。
    続いてcurlのバージョンを上げていきます。以下を実行していけばOK。
wget https://curl.haxx.se/download/curl-7.55.1.tar.gz
tar xfvz curl-7.55.1.tar.gz
cd curl-7.55.1 
/.cofigure --enable-libcurl-option
make
make install
  • 環境変数の設定
    これでrbenvが入れられそうなものですが、その前にrbenv周りの環境変数を設定してやる必要があります。
    どうもDockerfileに書いたやり方ではうまくいきませんでした。.bashrcとかに書いてやってもいいと思います。
    export PATH=$PATH:~/.rbenv/bin:~/.rbenv/shimsでとりあえず設定。

  • rubyのインストール
    ようやくrubyを入れられます。 先ほど後回しにしたrbenv install 2.3.3以降を実行すれば完了です。 おつかれさまでした。

やってみての所感

いきなりDockerfileを書いてbuildするとあちこち問題が起こるので、ベースのイメージを持ってきて、そこに一つ一つ入れたいものを入れていくほうがいいのかもしれません。
で、うまくできたらDockerfileにまとめておく、と。環境変数は結局どうやって書けばいいのか分からず…

Cookieを使ってユーザーごとに表示を出し分けてみた

あっという間に7月も終わりですね。目標にしていた月2更新が早くも途絶えそうなので記事を書きます。

先日、仕事で
「うちのサイトに登録して2週間以内の人にはこのポップを表示するようにしてほしい。でも、そのポップの隅の×印を押したら2週間以内だとしてもポップが表示されないようにしてほしい。クッキーとか使えばできるんでしょ?」
みたいな依頼を受けました。

でも、僕Cookie使った実装をしたことがなかったんですよね…恥ずかしながら。

今回は自前フレームワーク的なものが用意されていたので簡単に実装できたのですが、一度簡単にCookieの基礎知識をまとめておいたほうがいいなあと思って、今この記事を書いているわけです。


そもそもCookieとは

  • WebサーバーからブラウザへのHTTPレスポンスのヘッダーを利用した小さな情報(ファイル)。key-value型(クッキー名-値)の情報。
  • サイトアクセス時にWebサーバー側がCookieをsetし、ブラウザにはCookieファイルが保存される。
  • サイト再訪時、ブラウザはHTTPリクエストのヘッダーにCookieを入れてWebサーバーに送信する。
  • Cookieを使えばWebサーバー側はそのアクセスが初めてのアクセスなのか再訪なのかを判断できる。
  • PHPでは以下のようにCookieをsetする(らしい)。
setcookie(クッキー名, 値, Cookieの保存期間);
例えばこんな感じ
setcookie('hoge', 'fuga', time() + 60 * 60 * 24 * 30);
タイムスタンプの部分は
time();で現在日時を取得。その後は「秒 * 分 * 時間 * 日」。
上記の例では30日間Cookieを保存することになります。
なお、
setcookie('hoge', 'fuga', time() - 1);
のように現在より前の時間を設定してやるとCookieを削除することができます。

setcookieはドメイン名とかこれ以外にも引数をつけることができるらしいのですが、あんまり使わないようですね。
わざわざDBにデータ持たせるほどでもないかなーという時(今回のケース)や、まだログインはしていないけど再訪者をチェックして表示を出し分けたい時、ECサイトのカート機能やレコメンド機能で使うことが多いようです。


今回の場合、

  1. サイトアクセス時にCookieをgetする(close_pushed=1を持っているかチェックする)。
  2. Cookieがあった場合
    1. ポップを表示しないよう、jsでポップ部分のdiv要素を削除する。
  3. Cookieがなかった場合
    1. ポップ部分はそのまま表示する。
    2. ×ボタンが押された場合、ボタンのクリックイベントで関数を実行。その中でCookieをsetする(close_pushed=1をsetする)。と同時にjsでポップ部分のdiv要素を削除する。

という流れになりました。

前述の通り、今回はjsで作った自前フレームワーク的なものが用意されていたので、それを使って以下のような感じで簡単に書けました(一部にjQuery使用)。

<!-- 帯の部分のみ抜粋 -->
<div id="pop">
  <p>会員登録ありがとうございます。</p>
  <span><a href="#" onclick="closePop();return false;">×</a></span>
</div>
// アクセス時に実行
(function () {
  var cookie = new FwCookie(); // フレームワークの呼び出し
  // getCookie(クッキー名);でCookieの値を取れる
  if (cookie.getCookie('close_pushed')) {
    $('#pop').remove();
  }
}());

// ×ボタンがクリックされたら実行
function closePop() {
  var cookie = new FwCookie();
  // setCookie(クッキー名, 値);でCookieをsetできる
  cookie.setCookie('close_pushed', 1); 
  $('#pop').remove();
}

因みにCookieの保存期間はフレームワーク側で一律に設定しており、使う際にいちいち記述する必要が無いようになっていました。


セッションとの違いとかもまとめたかったのですが、長くなりそうなのでとりあえずこんなところで。

書いている人&このブログについて

書いている人について

こんにちは。hkと申します!

経歴

ECやFintech関連のサービスを展開する都内のIT企業でwebエンジニアをしています。職業エンジニア歴は(この記事を書いている時点で)まだ3ヶ月です。

学生時代に金融や経済を学んだものの興味が持てず、新卒でシステムベンダーに就職。過酷な環境に心を折られて1ヶ月で退職するも慌てて受けた公務員試験に合格。官公庁で3年働く間にプログラミングを独学し、今の会社に採ってもらいました。よかったよかった。

使っている言語・技術

現在の仕事はJava(Spring, Seasar2)、PHP(Zend Framework)あたりを使ったサーバーサイドの開発が中心です。OracleMySQLは触りますが、インフラは疎めです。フロント方面ではjQueryくらいしか触りません。

社内では他にRubyやAngular、Go、Pythonあたりを書く人もいますが、今私の携わっているサービスは比較的歴史が古いため、仕方ない気もします。

プライベートではPHPPythonでサイトを作ったことがあります。他には過去にRaspberryPiを弄ったり、iOSに手を出したり。最近はJS全般に興味津々、といったところです。

 

このブログについて

アウトプットによるスキルの定着を図りつつ、備忘録を兼ねてこのブログを始めることにしました。月2回の更新が目標です。

基本的にはその時々に学んだ技術をソースコードを交えてまとめていく感じのブログになると思います。「最近読んだ本や技術書でこれが良かった」みたいな記事も書くかもしれません。

正直なところ、ブログはほとんど書いたことがない上にマークダウンも書けるか怪しいので最初のうちは読み辛いブログになってしまうかもしれません。レベル的には未熟でも無味乾燥な記事にならないようにしたいです。少しずつ頑張っていこうと思います。

以上どうぞよろしくお願いします。