カテゴリー ‘ プログラミング

[FuelPHP] FuelPHPで作るログイン管理


 

5日目の@madmamorさんの「FuelPHPでFacebookアプリを作ってみよう。準備編。」に続きまして、

FuelPHP Advent Calendar 2011の6日目を書かせていただきます。@9ensanです。

今回は、FuelPHPをインストールすると「fuel/packages」フォルダに入ってくる「SimpleAuth」を使ったログイン管理システムの作り方です。

動作するサンプルは「こちら」になります。

まずは、初期設定です。

「fuel/packages/auth/config」フォルダ内にある2ファイル

  • auth.php
  • simpleauth.php

を「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とのベンチマークは、とても気になるところです。

長くなりましたが、読んで頂きありがとうございました。

FuelPHPのキャッシュライブラリ – File編


まずは、fileストレージ

File

まず、cacheのコンフィグファイルをapp配下にコピーします。

cp fuel/core/config/cache.php fuel/app/config/cache.php

以下のように「fuel/app/config/cache.php」の内容を設定

return array(
	'driver' => 'file',
	'expiration' => null,
	'file' => array(
		'path' => '',
	),
);

これで、「file」ストレージをキャッシュに使用する設定ができました。

pathは設定していないと、デフォルトでは「fuel/app/cache」に

キャッシュの内容を保存したファイルが作成されます。

とりあえず、以下の内容でキャッシュを生成して試してみる

コードの内容は、

コントローラー

  public function action_cache()
  {
    // String
    Cache::set('string', 'cache test');
    $data['string'] = Cache::get('string');

    // Array
    $a = array(1, 2, array('key' => 'value'));
    Cache::set('array', $a);
    $data['array'] = Cache::get('array');

    // Object
    $o = new Library_Test();
    Cache::set('object', $o);
    $data['object'] = Cache::get('object');

    $this->template->title = 'Test » Cache';
    $this->template->content = View::forge('test/cache', $data);
  }

View

<p>Cache</p>
<div>String:<?php var_export($string) ?></div>
<div>Array :<?php var_export($array) ?></div>
<div>Class :<?php var_export($object) ?></div>
</p>

こんな感じです。

すると、画面上では

こんな感じになります。

で実際にキャッシュファイルの内容を確認すると

「fuel/app/cache」に以下の3ファイルが出来ていました。

  • array.cache
  • object.cache
  • string.cache

中身は、

{{Fuel_Cache_Properties}}{"created":1322409987,"expiration":null,"dependencies":[],"content_handler":"string"}{{/Fuel_Cache_Properties}}cache test

こんな感じ、

作成日時が「created」に入るみたい。

あとで確認するけど、「expiration」「dependencies」には、setメソッドの引数で渡される、expiration, dependenciesの情報がそれぞれ入るだろうと予想。

で、上記は文字列を保存したstring.cacheの内容だが、文字列はそのまま保存される模様。

同様に、array.cache、object.cacheの内容は、

{{Fuel_Cache_Properties}}{"created":1322409987,"expiration":null,"dependencies":[],"content_handler":"serialized"}{{/Fuel_Cache_Properties}}a:3:{i:0;i:1;i:1;i:2;i:2;a:1:{s:3:"key";s:5:"value";}}
{{Fuel_Cache_Properties}}{"created":1322409987,"expiration":null,"dependencies":[],"content_handler":"serialized"}{{/Fuel_Cache_Properties}}O:12:"Library_Test":0:{}

こんな感じ、phpのserialize関数を使用して保存されるもようでした。

FuelPHPのキャッシュライブラリの各メソッドの使用方法


FuelPHPのCacheライブラリには以下の4つのメソッドが5つのメソッドがドキュメントに載っている

  • set
  • get
  • delete
  • delete_all
  • call

それぞれの関数がどのように動作するか確認していきます。

setメソッド

set($identifier, $contents = null, $expiration = false, $dependencies = array())

上記例では、expiration、dependenciesは使用しなかったのでどのように動作するか確認、

まずは、expiration、キャッシュの有効期間を指定してみる

  public function action_cache2()
  {
    // String
    Cache::set('string', 'cache expiration test', 2);
    $data['one'] = Cache::get('string');
    sleep(3);
    $data['three'] = Cache::get('string');

    $this->template->title = 'Test » Cache';
    $this->template->content = View::forge('test/cache2', $data);
  }

わざと、キャッシュの有効期限が切れるように3秒のsleepを入れてからキャッシュの取得を行うと

CacheExpiredExceptionが発生!

なるほど、FuelPHPでは、基本想定しない動作をするとExceptionで通知する仕組みのようだ。

ということでtry-catchを記入する

    // String
    Cache::set('string', 'cache expiration test', 2);
    $data['one'] = Cache::get('string');
    sleep(3);
    try {
      $data['three'] = Cache::get('string');
    } catch (CacheExpiredException $ex) {
      $data['three'] = $ex;
    }

    $this->template->title = 'Test » Cache';
    $this->template->content = View::forge('test/cache2', $data);

こんな感じで実行結果は

なるほど、なんかJavaを使ってた頃を思い出す…なつかしいけどこのこの感じ好きだ!

キャッシュの有効期限たキーを呼び出すと対象のキャッシュをdeleteしてからExceptionを呼んでるみたいなのでキャッシュのファイルはなくなっていました。

内容を確認する為に作りっぱなしにしてみた

{{Fuel_Cache_Properties}}{"created":1322413708,"expiration":1322413710,"dependencies":[],"content_handler":"string"}{{/Fuel_Cache_Properties}}cache expiration test

予想通り、expirationにtime()関数の結果をいれている模様。

今の時間がexpirationを過ぎていないかチェックして時間が経過していた場合にエラーとしていました。

次に「dependencies」これは、予想と動作が少し違ったので

coreのファイルの中を除いてみた、すると次のような事が分かった

キャシュにdependenciesが指定されていた場合、

  • dependenciesで指定された、キーのキャッシュが存在しない。
  • dependenciesで指定された、キーのキャッシュが元のcreatedより新しい(秒単位での比較で>)

が成立するとExceptionが発生する。

Fileストレージを選択した場合、dependenciesのキャッシュの中のcreatedやexpiration、dependeciesは、見てなくてファイルの作成日時を取得して比較していました。

面白いけど、秒単位での比較となるとうーん、微妙。。。

マイクロ秒で比較して欲しいと思うのですが、それでも正直微妙かもですが。

面白いけど、自分なら正直使わないかな。

 getメソッド

get($identifier, $use_expiration = true)

こちらでは「use_expiration」を使ってみる。

ソースはこんな感じ

  public function action_cache4()
  {
    // String
    Cache::set('string', 'cache expiration test', 2);
    sleep(3);
    $data['one'] = Cache::get('string', false);

    $this->template->title = 'Test » Cache';
    $this->template->content = View::forge('test/cache3', $data);
  }

動作は、「use_expiration」にfalseを設定すると有効期間を無視するように設計されていた。

2秒でキャッシュが無効になるところが3秒後にキャッシュデータを取得できた。

柔軟にキャッシュを扱えそうだ。

deleteメソッド

delete($identifier)

まず試してみる

ソースは

  public function action_cache_del()
  {
    // String
    Cache::set('string', 'cache expiration test');
    Cache::delete('string');
    $data['one'] = Cache::get('string');

    $this->template->title = 'Test » Cache';
    $this->template->content = View::forge('test/cache3', $data);
  }

こんな感じ

で、結果は

エラーが発生!!

deleteの次のgetでエラーが発生ちゃんとキャッシュのキーを元にキャシュ情報が削除されている模様

delete_allメソッド

delete_all($section = null, $driver = null)

試してみる、ソースは以下のような感じ

  public function action_cache_alldel()
  {
    // String
    Cache::set('string', 'cache expiration test');
    Cache::delete_all();

    $this->template->title = 'Test » Cache';
    $this->template->content = View::forge('test/cache3', $data);
  }

実行後にキャッシュのフォルダを除いてみると、
今まであった全てのキャッシュ情報が削除されました。

callメソッド

call($identifier, $callback, $args = array(), $expiration = null, $dependencies = array())

これは、何に使うんだろう???と謎だったのでソースよんでみました。

第1引数で渡したキーの値でキャッシュに問い合せて、

存在しなかったら、第2引数、第3引数を使用してPHPの「call_user_func_array」関数を呼び出す。

取得出来た結果をキャッシュに保存し、処理結果として呼び出し元に戻すという処理になっていた。

これは、これで中々の機能で面白い!!

FuelPHPでキャッシュを使用するならこのメソッドはかなりオススメなメソッドです。

長くなりましたが、

Fileでのキャッシュと各メソッドの機能を調べた結果でした。

次回は、APCでのキャッシュの方法を調べたいと思います。

FuelPHPでのキャッシュライブラリの調査


FuelPHPでの機能を1つずつ使って行こうと考えています。

まず第1回目は、「Cache」です。

いきなりキャッシュ?って思った人も我慢して下さい。

個人的に興味のある機能の使い方から調べています。

まず、使用する為のconfigファイルは、

各プロジェクトの

「fuel/core/config/cache.php」

にありました。

coreの中にconfigがあるの?と思いました。

多分coreの中のconfigを修正しなくても環境毎に変えられるようにできてるんじゃないのと思っています。

その調査はまた後日、

まず、用意されているcacheの方法として

  • file
  • apc
  • memcached
  • redis

の4種類が使用出来るようになっていました。

基本は、

configの設定でcacheのストレージを決めて、

staticなget、set、deleteのメソッドで関数の登録、取得、削除処理を行うようです。

次回は各メソッドの使い方を調べます。

FuelPHPのインストール(コマンドラインを使用)


FuelPHPでコマンドラインを使用したFuelPHPのインストール方法

公式ドキュメントのこちらのページを参考に行いました。

まず、

curl get.fuelphp.com/oil | sh

を実行となっていたが、何してるのか中身を少し除いてみた。

最初のcurlで取得しているoilの中で「installer.sh」というshファイルをダウンロードしてそれを

「/usr/bin」に「oil」という名前でダウンロードして実行権限を付与するという処理が書かれていた。

もし

「/usr/bin」の中を汚したくない人は独自にダウンロードして設定する必要があります。

その後、Webアプリケーションを設定したい箇所で

oil create <project_name>

を実行する。

そうするとgitからfuelphpをダウンロードして必要なフォルダ権限を付与してくれます。

作成されたプロジェクトフォルダに「public」というフォルダが作成されているので

このフォルダにWebサーバのDocumentRootを設定する事で動作します。

これでFuelPHPをとりあえず動かす事ができます。

 

return top