5日目の@madmamorさんの「FuelPHPでFacebookアプリを作ってみよう。準備編。」に続きまして、
FuelPHP Advent Calendar 2011の6日目を書かせていただきます。@9ensanです。
今回は、FuelPHPをインストールすると「fuel/packages」フォルダに入ってくる「SimpleAuth」を使ったログイン管理システムの作り方です。
動作するサンプルは「こちら」になります。
まずは、初期設定です。
「fuel/packages/auth/config」フォルダ内にある2ファイル
を「fuel/app/config」にコピーします。
「auth.php」を
return array(
'driver' => 'SimpleAuth',
'verify_multiple_logins' => false,
'salt' => '9ensan',
);
のように、
「simpleauth.php」を
'login_hash_salt' => '9ensan_login',
のように、修正します。
※両ファイルのsaltの付いた行に関しては、各個人で簡単に分からない文字列にしてください。
次に「fuel/app/config/config.php」を
/**
* Localization & internationalization settings
*/
'language' => 'ja', //'en', // Default language
'language_fallback' => 'en', // Fallback language when file isn't available for default language
'locale' => 'ja_JP', //'en_US', // PHP set_locale() setting, null to not set
'encoding' => 'UTF-8',
/**
* DateTime settings
*
* server_gmt_offset in seconds the server offset from gmt timestamp when time() is used
* default_timezone optional, if you want to change the server's default timezone
*/
'server_gmt_offset' => 3600 * 9, //0,
'default_timezone' => 'Asia/Tokyo', //'UTC',
のように修正します。
そして、「fuel/app/lang/」に「ja」フォルダを作成します。
そこに「validation.php」を作成し中身に以下の内容を記述します。
return array(
'required' => ':label は必須入力です。',
'min_length' => ':label は :param:1 文字以上で入力して下さい。',
'max_length' => ':label は :param:1 文字以下で入力して下さい。',
'valid_email' => ':label は メールの形式で入力して下さい。',
);
これは、validationエラー時に日本語でエラーメッセージを出力する為に用意しています。
dbが接続できる用に「db.php」も修正しておきます。
これでconfigファイルの準備はできました。
次にテーブルを作ります。
db.phpで接続するように設定しているデータベースに対して、以下のSQLを実行し「users」テーブルを作成します。
CREATE TABLE `users` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 50 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`password` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`group` INT NOT NULL DEFAULT 1 ,
`email` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`last_login` VARCHAR( 25 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`login_hash` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`profile_fields` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`created_at` INT( 11 ) UNSIGNED NOT NULL ,
UNIQUE (
`username` ,
`email`
)
)
こちらのテーブルは、「simpleauth.php」コンフィグファイル内で、
ログインに使用するテーブル名をusersと指定しているのでこの名前で作成します。
もし、別名に変更する場合「simpleauth.php」コンフィグファイル内も修正が必要になります。
これで、SimpleAuthを使用する準備はできました。
まず、用意するメソッドですが、今回は以下のメソッドを用意します。
- before() // 前処理
- action_404() // ページが見つからない
- action_timeout() // 不正なページアクセス
- action_logined() // ログイン済み画面
- validate_login() // ログイン入力チェック
- action_login() // ログイン処理
- action_logout() // ログアウト
- action_create() // ユーザー作成入力画面
- validate_create() // ユーザー作成入力チェック
- action_created() // ユーザー作成処理
- action_update() // ユーザー更新入力画面
- validate_update() // ユーザー更新入力チェック
- action_updated() // ユーザー更新処理
- action_remove() // ユーザー削除確認画面
- action_removed() // ユーザー削除処理
まずは、前処理から
public function before()
{
parent::before();
// 初期処理
// POSTチェック
$post_methods = array(
'created',
'updated',
'removed',
);
$method = Uri::segment(2);
if (Input::method() !== 'POST' && in_array($method, $post_methods)) {
Response::redirect('auth/timeout');
}
// ログインチェック
$auth_methods = array(
'logined',
'logout',
'update',
'remove',
);
if (in_array($method, $auth_methods) && !Auth::check()) {
Response::redirect('auth/login');
}
// ログイン済みチェック
$nologin_methods = array(
'login',
);
if (in_array($method, $nologin_methods) && Auth::check()) {
Response::redirect('auth/logined');
}
// CSRFチェック
if (Input::method() === 'POST') {
if (!Security::check_token()) {
Response::redirect('auth/timeout');
}
}
}
ここでは、「Auth::check()」と「Security::check_token()」が重要な処理になります。
「Auth::check()」は、既にログイン済みかどうかのチェックになります。
ログインしていないと表示しては、まずいメソッドをログインしていないのに呼ばれた場合はログインページへリダイレクトしています。
「Security::check_token()」は、CSRFを防ぐ為にtokenのチェックをしています。
tokenの仕込みは、view側で、
<input type="hidden" name="<?php echo \Config::get('security.csrf_token_key');?>" value="<?php echo \Security::fetch_token();?>" />
のように記述し、hiddenにtokenを設定しています。
ちなみに、「before」メソッドは、FuelPHPでは、コンストラクタの代わりに、初期処理を記述するメソッドです。
ですので、Controllerで実装する共通処理は「before」メソッドで記述するのがいいと思います。
次にログイン処理ですが
public function action_login()
{
// ログイン処理
$username = Input::post('username', null);
$password = Input::post('password', null);
$result_validate = '';
if ($username !== null && $password !== null) {
$validation = $this->validate_login();
$errors = $validation->error();
if (empty($errors)) {
// ログイン認証を行う
$auth = Auth::instance();
if ($auth->login($username, $password)) {
// ログイン成功
Response::redirect('auth/logined');
}
$result_validate = "ログインに失敗しました。";
} else {
$result_validate = $validation->show_errors();
}
}
$this->template->title = 'ログイン';
$this->template->content = View::forge('auth/login');
$this->template->content->set_safe('errmsg', $result_validate);
}
このようになっていて
重要なのは、12、13行目のAuthのインスタンス生成部分とloginメソッドの使い方です。
Authのインスタンス「auth.php」コンフィグで「'driver'
=>
'SimpleAuth'
,
」と設定してたので、
自動的にSimpleAuthのインスタンスが生成されます。
そして「$auth->login($username, $password)」では、パラメータで取得出来た、
ユーザー名とパスワードをチェックします。
ログインに成功するとtrueを、失敗すると、falseを返します。
ですので、ログインできたらログイン後画面にリダイレクトし、失敗した場合は、そのままエラー画面を表示しています。
次に、ログアウト
Auth::logout();
この1文でログアウトができます。
次に、ユーザーの登録処理
$auth->create_user($input['username'], $input['password'], $input['email'])
ユーザー名、パスワード、メールアドレスを渡して登録します。
失敗したら、falseが戻ってくるか、Exceptionが発生するので適時上手く処理する必要があります。
このメソッドには実は、隠れた第4引数、第5引数があり、
第5引数は、プロフィール情報を配列で渡すと「serialize」してデータベースに格納してくれます。
RDBの恩恵は消えますが、様々なプロフィールを登録出来る仕組みは「SimpleAuth」は保持しています。
次に、ユーザー情報更新処理
$auth->update_user($values, $username)
このように、ユーザー名をキーに更新対象を連想配列で渡します。
成功するとtrue、失敗するとfalseまたは、Exceptionが発生します。
こちらも適時上手く処理擦る必要があると思います。
次に、ユーザー削除処理
$auth->delete_user(Input::post('username', null));
Auth::logout();
削除後に、ログアウトするようにしてください。
こちらも削除に失敗するとExceptionが発生するので上手く処理してください。
FuelPHPでは、想定外の処理が起きると例外(Exception)を投げる処理があります。
これは、いいか悪いかは、人によって意見が分かれると思いますが、
上手く処理をしておかないと思いも寄らずに、通っていると思っていた処理が通らないなどという事に陥りかねないので
注意が必要だと思います。
今回作成した、ログイン処理は、「こちらに」app以下のファイルをアップしてあります。
参考にして頂ければと思います。
また、まずい箇所がありましたら、指摘して頂けたらと思います。
7日目のFuelPHP Advent Calendar 2011は、@tao_sさんによる
「FuelPHPとCodeIgniterでCMS作ってパフォーマンスを比べてみた」です。
私もCodeIgniterからの移籍組なのでCIとのベンチマークは、とても気になるところです。
長くなりましたが、読んで頂きありがとうございました。