サンゴラボ

4年目ソシャゲエンジニア

PHPのクッキーとセッション

このブログではPHPフレームワーク(CodeigniterとかFuelPHP)について書いていこうかと思ってたけど、僕のPHP経験がなさすぎてちゃんとしたことが書けないことに気づいた(そもそもエンジニアとしての経験がゼロに等しい)。そこで、わからないことについては素直に基礎からまとめていこうと思います。

とりあえず今回はWeb業界にいてもPHPを勉強していても必ず出てくるクッキーとセッションについてまとめておきます。あくまで自分用のメモです。

この2つのワードは働いていてもよく出てくるのですが、なんとなくわかってる状態だったので、ちゃんと理解しないとヤバいなと感じていました。

クッキーとセッションを理解するための大前提は、HTTPはステートレスなプロトコルであるということです。つまり、HTTPリクエストは毎回独立したものであるということです。

そのため、Webではページ間で情報を共有することができないということになります。それを解決するために、クッキーやセッションが使われています。

以下PHPに絡めた話

■クッキー

  • クッキーはクライアントに保存可能な小さなテキストのこと
  • サーバはクライアント上のクッキーを勝手に読み書きできる
クライアント・サーバ間のクッキー情報の授受はHTTPヘッダで行われる。
  • レスポンスヘッダのSet-Cookie
  • リクエストヘッダのCookie
PHPでは
  • setcookie関数:レスポンスヘッダにSet-Cookieヘッダを追加
Set-Cookie: url=http%3A%2F%2F35lab.hateblo.jp%2F; expires=Sun, 02-Dec-2012 18:26:17 GMT
  • $_COOKIE変数:リクエストヘッダのCookieヘッダの参照
Cookie: url=http%3A%2F%2F35lab.hateblo.jp%2F
クッキーの問題点
  • name(クッキー名)=value(値)の形でデータそのものがクライアントに保存されている
  • 実データがネットワーク上を流れるので簡単に見ることができる

■セッション

  • セッションはデータをサーバ側で管理する
  • クライアント側にはセッションIDだけを保存
PHPでは

session_start関数でセッションを開始する。セッションを開始した後のレスポンスにはSet-CookieヘッダとしてPHPSESSIDという名前のクッキーが送信される。

Set-Cookie: PHPSESSID=lrg9amcqb7646tgtih5fd0uap3; path=/

クライアントからのリクエスト時はCookieヘッダでPHPSESSIDが送信される。ここで、クライアントー・サーバ間でやりとりされるのはセッションIDだけであることがポイントである。サーバで管理されるセッション情報の読み書きはは$_SESSIONを介して行われる。

セッションIDを入手できれば、なりすましは可能。しかし、セッションIDはセッションが切れたら無効になるので、リアルタイムに盗聴しないかぎり、なりすましは難しい。セッションはブラウザを閉じれば切れる。また、session_regenerate_id関数を使えば、セッションの途中でセッションIDはを再作成することができる。


最近HTTPと仲良くなってきた気がする。あとは自動ログインの仕組みとか、各フレームワークにおけるセッションの実装とか知りたいところ。

FuelPHPでモジュールを使ったときのユニットテスト

FuelPHPでソースコードを機能毎にモジュール分割したときに、ユニットテストが動かせなくて苦労しました。なんとかテストを走らせることができたので手順をまとめておきます。ちなみにやったのはモデルのテストだけです。

1. PHPUnitの設定ファイル(phpunit.xml)の編集

参考:unit_tests_for_modules

fuel/core/phpunit.xmlを直接編集するのではなく、まずはfuel/appにコピーする。

FuelPHP内でPHPUnitにテスト用のファイルとして認識されるのは、デフォルトでは以下の3つのディレクトリ配下のみです。

  • fuel/core/tests ・・・コアクラスのテスト
  • fuel/app/tests ・・・アプリケーションのテスト。
  • fuel/packages/*/tests ・・・パッケージのテスト

なので、モジュール分割したときのテストファイルを置く場所を設定します。公式ドキュメントにも例として書かれているので、以下をコピーしたphpunit.xmlの<testsuites></testsuites>に追記します。

<testsuite name="modules">
 <directory suffix=".php">../app/modules/*/tests</directory>
</testsuite>

これで、/fuel/app/modules/*/tests配下にあるファイルがテストケースファイルとして認識されます。


2. テストケースクラスの@groupアノテーションで「Modules」を指定

1.でtestsuite要素のname属性の値をmodulesにしたので、テストケースクラスの@groupアノテーションにはModulesを指定します。MakeGoodを使えばアノテーションを指定しなくてもテストを実行できます。

<?php
namespace Mymodule //名前空間の指定を忘れずに!
/**
 * Unit Tests for Modules
 *
 * @group Modules
 */
class Test_Testclassname extends \TestCase
{
    // テスメソッド
}

次のように、oilコマンドでモジュールにあるテストを実行できます。

oil test --group=Modules


3. テストケースクラスでのモジュールの読み込み

参考:FuelPHP how to load model in test? and how to load and test controller?

一番つまづいたのがモデルの読み込みのとこです。モジュール分割してもコントローラからは問題なくモデルを読み込めたので、名前空間だけ合わせればテストケースでも同じように読み込めると思ってました。

参考ページによると、モジュールはURL通してコントローラにアクセスしたときに自動的にロードされるらしく、今回のようなテスト(oil)経由での実行時は、モジュールを手動で読み込まないとだめらしい。てことで、モジュール分割した場合は、テストケースのsetUpBeforeClass()メソッドあたりで次のようにモジュールを読み込む必要があります。

\Module::load('mymodule');


あと、config.phpのAlways Loadでモジュールを自動読み込みすることもできたけど、なんかしっくりこなかったし、テスト以外でもロードされるのでやめました。test用のconfig.php用意するならアリかなと思ったのですが、それは上手く行かなかった。ちなみにbootstrap.phpでテスト環境にすれば上手くいきました。

URI設計に悩んで開発が進まない

最近CodeIgniterやFuelPHPでシステムを作っててURI設計を意識するようになりました。
理由としてはCodeIgniterやFuelPHPにおけるURLのセグメントが、コントローラのクラス、
メソッド名、メソッドの引数名に関係しているからです。


CodeIgniterにおけるURLセグメントの例:

 hogehoge.com/class/function/ID 

第1セグメント(class)がコントローラのクラスに対応
第2セグメント(function)がコントローラのメソッド名に対応
第3セグメント(ID)がメソッドに渡す引数に対応

とても直感的使いやすいのですが、URI設計という言葉を聞いていろいろ試行錯誤中です。なんとなくわかるようで、実際に設計するとなるとわからない。


てことでとりあえず調査。

第20回 “使いやすいURI(URL)”の設計を考える

たかが URI の設計、されど URI の設計

RESTful Web アプリの設計レビューの話


書いてあることは納得できることばかりですが、今までは全然意識してなかったです。挙げられているURI設計の指針をいくつか抽出しました。

  • 短くて入力しやすいURLにする
  • わかりやすい(記述的な)URIにする
  • サイトの構造をきちんと表す
  • マジックナンバーを使わない
  • 動詞ではなく名詞にする


結構ユーザ目線の事柄が多いですが、URI設計をしっかりすることは開発者にとっても利点があると個人的に感じました。開発者はユーザよりはるかにURLを直打ちしているので、URLの意味や構造がしっかりしていることはシステムの理解につながると思います。

特にCodeIgniterやFuelPHPのようにURLセグメントがソースコードと密接に関係しているので、良いURI設計はシステムの全体像を把握する助けになりそうです。

URI設計について概要は理解できたかな、という感じですが、実際のシステムの設計では結構苦労しています。原因はシステム特有であったり、CodeIgniterやFuelPHPならではであったりと、いろいろあります。話が変わってしまうので、別記事で書こうと思います。