ラベル PHP の投稿を表示しています。 すべての投稿を表示
ラベル PHP の投稿を表示しています。 すべての投稿を表示

2014年6月5日木曜日

Sinatra・PadrinoでセッションIDを変更する

Webアプリケーションでは例えばログインやログアウトしたタイミングなど、セッションハイジャックのリスクを下げるためにセッションIDを変更したほうがよい場面があります。

PHPですと、言語に組み込みでsession_regenerate_idという関数が用意されています。さすがWebに特化した言語ですね。

で、Rubyでは言語そのものにセッションIDを変更する方法はありません。各フレームワーク依存ですね。ということで、軽量フレームワークとしてよく使われるSinatraやその派生のPadrinoにおいてセッションIDを変更する方法を調べてみました。

ます、セッション内容を破棄して構わないのであれば、

session.destroy

と単にdestoryメソッドを呼んでセッションを破棄するだけです。自動的に新しいセッションIDでセッションが再生成されます。

セッション内容を引き継ぎたい場合は、事前にセッション内容を取得しておき、
新しいセッションの内容としてまるごと置き換えます。

old_session_hash = session.to_hash
session.destroy
session.replace(old_session_hash)

Padrinoの場合、以下の様な感じでヘルパーメソッドにしておくとよいでしょう。メソッド名はphpのマネです。ヘルパーを定義している部分に適当に追加すればいいと思います。

# セッションIDを再生成する
# @return [void]
def session_regenerate_id
  old_session_hash = session.to_hash
  session.destroy
  session.replace(old_session_hash)
end

上記 session_regenerate_id を呼べば、セッションIDが変更されてセッション内容が引き継がれます。

※2014/06/12追記
RackミドルウェアでCSRF対策をしている場合には、セッションIDの変更とともに、セッション内に保持しているCSRFトークンも変更したいと思うでしょう。そういう時は、引き継ぐセッション情報からCSRFトークンの情報を削っておくと、自動的にCSRFトークンを再生成してくれます。ということで修正したコードを載せておきます。

# セッションIDを再生成する
# @return [void]
def session_regenerate_id
  old_session_hash = session.to_hash
  old_session_hash.delete('csrf')
  session.destroy
  session.replace(old_session_hash)
end

上記の例はCSRFトークンをセッションに格納する際のキーが"csrf"である場合です。このキーは状況に応じて変更してください。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年5月21日水曜日

Rubyのコメント形式とYARD

PHPの時はPhpDoc形式のコメントをIDEが読み取って連携してくれるという事情もあり、ソースコードにはPhpDoc形式のコメントをつけるようにしてました。このPhpDocでは様々なタグを付けることができて、例えば関数の引数は@paramタグで指定できたりします。

ではRubyの場合はどうかと思って、今さらながら調べてみました。Rubyの場合、ソースコード内に記述するコメントのパーサとしてはRDocが代表的みたいですね。

調べてみると、RDocのコメントには、特に関数の引数や引数の型を指定する形式とか、そういうのはないみたいです。ちょっとイメージが湧かないので、有名なライブラリのソースコードをあたってみました。

ActiveRecordの場合、クラスやモジュールの先頭にガッツリ長文で説明が例も交えて解説してあります。

Rackの場合、ドバっと書いてあるファイルと、全然書いてないファイルの差が激しいです。まあ、必要なとこだけ絞って書いてあるんでしょう。

正直、決まりとか慣例とかあまり無いように思いました。うーん、自由に書けばいいのかなぁ。

などと思っていたら、どうやら、PhpDocに似たYARDってのがあるらしいじゃないですか。
※詳細はリンク先参照。
参考1 http://d.hatena.ne.jp/kitamomonga/20110825/ruby_yardoc_tag
参考2 http://morizyun.github.io/blog/yard-rails-ruby-gem-document-html/

そうそう、こういうのを探してたわけですよ。これならPhpDocと同じような感覚で書けますね。YARD自体の解説は上記リンク先に素晴らしい解説があるのでここではしませんが、やっぱりソースコードにコメントを入れるものとしては引数と戻り値を指定するタグくらいはあって欲しいわけで、そういう意味ではYARDはバッチリですな。

というわけで、今後YARD形式でコメントを書いていこうと思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年5月10日土曜日

Safariで"戻る・進む"時のキャッシュを無効にする

Webアプリの開発時に、ブラウザの戻る・進むボタンを押した時にキャッシュを使われるのは時として都合が悪いことがあります。そういう時は、HTTPレスポンスヘッダを設定するのが一つの手段です。

ちなみにPHPですと、このキャッシュを無効化する機能はキャッシュリミッタとして言語に標準で実装されていたりします。さすがWebアプリに特化した言語ですよね。
http://www.php.net/manual/ja/function.session-cache-limiter.php

上記マニュアルによれば、該当するヘッダは

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

ですね。そこで、現在Rubyで開発しているシステムで同様のレスポンスヘッダを設定してみたところ、上手くいくと思ったらこれがSafariだと効きません・・・。

色々レスポンスヘッダをいじってみますが、結局ダメでした。ちなみに調べてみるとヘッダでもHTMLのメタタグでもダメで、Javascriptに頼るしかないようです。
http://stackoverflow.com/questions/11979156/mobile-safari-back-button

上記URLによると、次のようなスクリプトを使えばよいようです。

window.onpageshow = function(event) {
  if (event.persisted) {
    window.location.reload()
  }
};

URL中の説明にもありますが、jQuery経由では動作しないので生のJavascriptで書きます。これで Safari でも"戻る・進む"時にキャッシュではなくサーバから読むようになります。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月29日火曜日

PHPで、一時的に出力を抑制する

とあるオープンソースのコードを眺めていたら、下記のような記述がいくつもの箇所に使われているのを見ました。

ob_start();
〜何らかの処理〜
if (ob_get_level()) ob_end_clean();

調べてみると、ob_start()は出力のバッファリングをオンにして、すぐさま出力がされなくなります。例えば、ob_start()以降の処理で何らかのエラーが起きて出力がなされたとしても、それが画面に表示されないということです。

ob_get_level()は、出力のバッファリングのネストレベルを取得します。ob_start()はネストすることが出来て、そのネストレベル分解除しないといけません。

で、ob_end_clean()は、バッファ内の出力を破棄して(実際に出力を行わず)バッファリングを解除する関数です。

これらをまとめると、つまり、ob_start() から ob_end_clean() のまでの間の処理による出力は行われないということです。こういうやり方もあるんだなぁ。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年3月20日木曜日

[Ruby]開発環境をEclipse(Aptana)からVimに変更した件

開発環境にはEclipseを愛用してきた僕ですけれども、Rubyでの開発プロジェクトを本格的に進めるにあたり、色々試行錯誤の結果Vimに乗り換えることにしました。いえ、乗り換えるというと語弊がありますね。正確に言えば、コーディングすなわちソースコードをガリガリ書く部分にはVimを使いますが、EclipseはGitリポジトリの状態を見るのに使ったりするので併用していく方式にした、ということです。適材適所。

PHPの時にはEclipseのPDTプラグインが大変良く働いて、例えば文脈に応じての補完機能などは非常に便利でした。これは動的にコードから補完ができる優れ物で、自分で書いたクラス定義を参照してインスタンスのメソッド名を補完できたりしたんですね。さらに、フレームワークのソースコードをライブラリを読み込ませることで、フレームワークに用意されたクラスやクラス内のメソッドまで補完が効きました。あとクラスやメソッドにカーソルを合わせてショートカットで定義元にジャンプできたりとか。

一方、EclipseでRuby開発に使えるプラグインとしてはAptana Studio3がありますが、動的にコードから補完するところまではできないようでした。また、フレームワークのクラス名やメソッド名も補完が働きませんでした。もしかしたら僕の設定が間違っていた可能性もありますが、ある程度時間を掛けたところで諦めました。

そもそも、純粋なテキストエディタとしての使い勝手としてはVimが好きで、EclipseにVim風のキーバインドを実現するプラグインのvrapperを入れて愛用していたくらいです。PHPで開発していた時には、文脈を理解した動的な補完とライブラリからの補完がよく出来ていたので書きやすさを少し犠牲にしてEclipseを使っていましたが、それがイマイチならEclipseを使う優位性は薄れてしまいます。

調べてみると、Vimで一定レベルの補完や自動文法チェックもプラグインでできるので、それならRubyを書くのにはVimの方がいいかと思ったんですね。ということでコーディングはVimで行うことにしました。

ちなみに、Gitリポジトリの状態を見るためにEclipseは併用します。コミットグラフが見やすいので。ヒストリービューはほぼリアルタイム(長くても5秒くらいの遅延)でコミットグラフを更新してくれるので、状態を把握しつつブランチ間を移動したりコミットしたりできます。Eclipseは検索なんかも結果が見やすいですし。タスク・タグの一覧とかも便利です。普段はVimでコードを書きつつ、裏でEclipseを起動させておいて必要な時だけ見る、という使い方になると思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年3月7日金曜日

一番経験あるのはPHPだけど一番好きなのはRuby

Web系アプリソフトウェア開発者としての僕のキャリアにおいて、開発に使用したプログラミング言語は大半がPHPです。だから最も経験があって慣れているのはPHPなんですけれども、でも一番好きかと言われると、そうでは無いですね。

なんていうか、PHPって気をつけないと行儀の悪いプログラミングが容易に出来てしまいますからね。プロジェクトによってはソースコードが無法地帯で世紀末と化している場合もあります。書いたプログラマの秘孔を突きたくなりますができません。残念。

じゃあ一番好きな言語は何だと言われれば、そりゃやっぱりRubyです。学生時代の頃、研究室で自分の研究をサボりつつする傍ら、Rubyで皆が研究で使うツールを開発していたことがありまして、その時にRubyの魅力に浸かりました。

Rubyはやりたいことが素直に書けるのが魅力ですね。Rubyを作ったまつもとゆきひろ氏も、書いていて楽しくなるような言語にしたと確か言ってましたし、実際そのとおりだと思います。

ついでに言うと僕がオブジェクト指向について初めてまともに理解したのもRubyを書いている時であり、オブジェクト指向によるプログラミングを初めて本格的に行った言語でもあります。その意味でも思い入れがあるんですよね。

で、今進めているプロジェクトでは、メインの部分で僕が自分で使う言語を決めていい状況にあり、ついに仕事でRubyをメインに使えるということで非常にワクワクしてます。今ちょうどRuby周りを準備中でテンション高いです。そのうちこのブログにもRuby関係の投稿をしていけると思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年2月20日木曜日

[PHP]グローバル変数を使っているファイルをインクルードするときの対処

チームで共有しているライブラリにグローバル変数や関数が定義されていて、それを読み込んで使う状況ってあるよね。

PHPの場合だとオブジェクト指向を意識せずに書けてしまうので、クラス化されていない外部ライブラリを読み込むなんて状況もありうるわけで、その場合にはグローバル変数や関数が使われていることもあるだろう。

で、自分が書くクラスでもそのグローバル変数や関数を使うわけだが、いくつかやり方がある。ということで、今回はグローバル変数について自分の書くクラスで使う方法をいくつか挙げてみようと思う。(グローバル関数の方はまた別の機会で)

例えばグローバル変数を次のように定義したファイルがあるとしよう。

<?php
$a = 1;

このファイルをインクルードして、クラス内部で使うことを考える。


1. global 宣言をつける

<?php
include 'inc.php';

class Foo {
  public function bar() {
    global $a;
    return $a + 2;
  }
}

$f = new Foo();
echo $f->bar();
echo "\n";

bar()メソッド内部で普通に変数$aを呼んでもグローバル変数と見なされないが、global宣言をした変数についてはグローバル変数として扱うようになる。ただ、僕個人の意見としては、これは極力使わないほうがいい。ついついグローバルスコープと意識せずに$aを変更するコードを書いてしまい、バグの原因となりかねないからだ。


2. スーパーグローバル変数 $GLOBALS を使う

<?php
include 'inc.php';

class Foo {
  public function bar() {
    $a = $GLOBALS['a'];
    return $a + 2;
  }
}

$f = new Foo();
echo $f->bar();
echo "\n";

こちらは、グローバル変数 $GLOBALS を使うパターン。$GLOBALSはグローバル変数名をキーとし、グローバル変数を要素として持つ配列である。グローバル変数であることを明示している分、1.よりはマシと思う。いちいち$GLOBALS['a']と書くには面倒だし一旦ローカル変数に代入している。phpでは配列の代入はコピーとなるため、グローバル変数を予期せず変更してしまうリスクも回避できる。
しかし、このコードも、クラスの内部にグローバル変数を直接参照するコードが入ってしまう箇所があるのはよろしくない。なぜなら実際にはクラス定義の部分だけ別ファイルにしてインクルードすることが多いし、そうするとグローバル変数が原因のバグが発生した時のデバッグが大変だ。その点については1.と変わらない。


3. コンストラクタの引数として受け取り、インスタンス変数に格納する

<?php
include 'inc.php';

class Foo {
  protected $a;

  public function __construct($a) {
    $this->a = $a;
  }

  public function bar() {
    return $this->a + 2;
  }
}

$f = new Foo($a);
echo $f->bar();
echo "\n";


ということで、コンストラクタの引数でグローバル変数を受けとるパターン。これでクラス内部にグローバル変数を直接参照するコードはなくなった。インスタンス変数に代入しているので、クラス内のメソッドからは自由に使える。僕はこのパターンを使っている。やはりクラスの定義を書いている時はそのクラス内部で色々完結させたい訳で、グローバル変数は外へ出すのが一番いいと思う。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年2月18日火曜日

PHPのタイプヒンティングは配列の参照渡しの時も有効

PHPのタイプヒンティングはバグの防止につながるので積極的に使っている。ちょっと気になったのが、配列の参照渡しの時には動作は変わらないのかということだった。

タイプヒンティングは、関数やクラスメソッドの引数が、特定のクラスに属するインスタンスであることや特定のインターフェースを実装していること、あるいは配列であることなどを強制する。たとえば、fooメソッドの引数$argが配列でなければならない時は、次のように書く。
protected function foo(array $arg) {
  ...
}

と、ここまでは公式リファレンスにも書いてある通りだ。で、僕が気になったのは、次のように引数を参照渡しにするときにも、同様にタイプヒンティングが有効なのかどうかだ。
protected function foo(array &$arg) {
  ...
}

では実際に試してみよう。次のような簡単なプログラムを用意する。testClassのメソッドfooの引数は配列を想定しており、ここでタイプヒンティングを使っている。
<?php
class testClass {
  public function foo(array $arg) {
    foreach ($arg as $key => $val) {
      print $val . "\n";
      $arg[$key] += 1;
    }
  }
}

$test = new testClass();
$arg = array(1, 2, 3);
echo "first\n";
$test->foo($arg);
echo "second\n";
$test->foo($arg);

$arg2 = 'string';
$test->foo($arg2);

これを実行すると、次のような結果が得られる。
first
1
2
3
second
1
2
3

Catchable fatal error: Argument 1 passed to testClass::foo() must be of the type array, string given, called in /path/to/phpfile/test.php on line 19 and defined in /path/to/phpfile/test.php on line 3

タイプヒンティングにより、配列以外の引数を与えたことでエラーとなった。
では次に、メソッドfooの引数を参照渡しにしてみる。(1行だけ変更)
<?php
class testClass {
  // public function foo(array $arg) { // 変更前
  public function foo(array &$arg) {
    foreach ($arg as $key => $val) {
      print $val . "\n";
      $arg[$key] += 1;
    }
  }
}

$test = new testClass();
$arg = array(1, 2, 3);
echo "first\n";
$test->foo($arg);
echo "second\n";
$test->foo($arg);

$arg2 = 'string';
$test->foo($arg2);

これを実行すると、次のような結果が得られた。
first
1
2
3
second
2
3
4

Catchable fatal error: Argument 1 passed to testClass::foo() must be of the type array, string given, called in /path/to/phpfile/test2.php on line 20 and defined in /path/to/phpfile/test2.php on line 4

参照渡しにしたことにより、引数として渡した元の配列の中身が変化し、先ほどと違ってメソッドを2回呼ぶと結果が変わっている。そして、参照渡しにしたときもタイプヒンティングは参照渡しにしない時と全く同様に動作した。

ということで、配列で参照渡しの時もタイプヒンティングは気にせず使って大丈夫。まあよく考えれば、オブジェクトのインスタンスを渡す時は参照渡しだから、それと同じ動作と考えれば当然か。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年2月14日金曜日

SmartyのデリミタをHTMLコメントにした時にタグ中の属性制御で文法エラーにしない方法

SmartyのデリミタをHTMLコメント(で囲む)形式にすると、テンプレートファイルをHTMLとしてエディタで扱うことができ、シンタックスのハイライトを効かせて色分けできるメリットがある。さらにはエディタのHTML文法チェック機能も使えるから、記述効率もアップしてバグも防げる。

だからデリミタを例えば <!--{ と }--> に設定しているプロジェクトも結構あると思う。これでエディタでシンタックスハイライトと文法チェックもできてパッピー!・・・と思いきや、ちょっと問題があるんだよな。

それは、タグ中の属性を制御したい場合。例えば、ラジオボタンやチェックボックスをチェックしているかどうかは、タグ中にchecked属性が存在しているかどうかで決まるから、条件によってチェックを入れたり外したりするには、HTMLタグの中にSmartyのデリミタを書くことになる。これが文法エラーになるわけ。checked属性だけでなくdisabled属性も同じだよね。具体的には、例えばこんな感じ。
<input type="checkbox" name="chk1" value="val1"
  <!--{if $cond1}--> checked="checked"<!--{/if}-->
  <!--{if $cond2}--> disabled="disabled"<!--{/if}-->
/>

上の例は、チェックボックスで$cond1がtrueの時にチェックを入れ、$cond2がtrueの時は操作できなくするもの。だがこれは当然HTMLの文法違反になる。まあ、Smarty通すから文法エラーなんか無視すれば問題ないと言えばそうなんだけど、だったらなんでわざわざデリミタをHTMLコメントで囲う形式にしたのかって話になってしまう。

そこで、少々トリッキーだが、次のようにすることで文法エラーを回避できる。
<input type="checkbox" name="chk1" value="val1"
  data-dummy1="<!--{if $cond1}-->" checked="checked<!--{/if}-->"
  data-dummy2="<!--{if $cond2}-->" disabled="disabled<!--{/if}-->"
/>

ダミーの属性を追加して左右のデリミタを共にダブルクオーテーションの内側に収めたのがポイントだ。これで例えば$cond1と$cond2がtrueの時は、
<input type="checkbox" name="chk1" value="val1"
  data-dummy1="" checked="checked"
  data-dummy2="" disabled="disabled"
/>

$cond1と$cond2がfalseの時は、
<input type="checkbox" name="chk1" value="val1"
  data-dummy1=""
  data-dummy2=""
/>

となるわけだ。data-*という属性はご存知HTML5の独自定義属性の書き方に従っている。ダミーだと分かりやすいように名前をつけるといいと思う。

美しいやり方ではないけれど、エディタや統合開発環境の文法チェックを活かせるという意味で実用的なメリットは有ると思う。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年2月13日木曜日

PHPなど動的型付け言語では変数名や関数名は長くていい

PHPなどの動的型付け言語って、Javaなどの型をはっきりさせる言語と違ってEcliseなどの統合開発環境による補完や定義の参照などが効きにくいところがある。

例えば、Javaの場合はインスタンスがコード中に登場したら、型が決まっているからメソッドの候補は自動的に決まり、例えばEclipseを使っていると候補がきっちり出てきてくれる。ところが、PHPの場合は、それがどのクラスのインスタンスなのか、いやそもそもインスタンスなのかどうかすら決まっていないから補完の候補が出せなかったりする。もちろん、EclipseのPDTなんかだと、ある程度文脈を読んでくれるから補完も出せるが、それだっていつも出せるわけじゃない。ということで、PHPを使う人間はしばしば、クラスの定義を自分で探して、どんなメソッドがあるか直接コードから探したりすることがある。

あるいは逆に、コードを読んでいて登場したメソッドがどんな働きをするのか、Javaであれば定義元にショートカット一発で飛んでいけるような場合も、PHPだとそれができないなんてこともある。そういうときも、メソッドを自分で探すことになる。

今述べたのはメソッドの例だけれども、これはインスタンスとか変数名とか関数でも同じようなことが言えて、要するに動的型付け言語では、候補探しや定義元の参照をしたいときには、既存のコードの中から探すという行為が発生しがちなのだ。

その際には既存のコードを一つ一つ探すのは大変だから、検索することになる。Eclipseの検索機能はPHPで開発してる時には上記の目的でよく使う。コードを横断的に検索し、結果を分かりやすく表示してくれるから、統合開発環境の検索機能はコマンドラインでgrepやfindを打つよりもずっと使いやすい。

その時に、スコープが分かれているからといって同じ変数名・関数名・メソッド名などをコードの色々な箇所で使っていると、目的のものを探し出しにくい。いや、もちろん言語仕様的には全く問題ないし、むしろ同じ目的の変数・関数・メソッドの名前を統一したほうがコード体系としては筋が通っているのかもしれない。だがしかし、開発をスムーズに進めていく上では、別の場所に登場した変数名・関数名・メソッド名は、たとえ同じ目的でも違う名前を付けていった方がいいと思う。

よって、区別のために色々と接頭辞や接尾辞をつけていくという意味で、変数名・関数名・メソッド名等は長くていいっていうことになるのだ。だから僕はPHPのコードを書く時にはわざと長めの関数名をつけたりするんだよね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。