カテゴリー ‘ FuelPHP

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


今回はmemcachedストレージ

Memcached

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

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

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

return array(
  'driver' => 'memcached',
  'expiration' => null,
  'memcached'  => array(
    'cache_id'  => 'fuel',
    'servers'   => array(
      array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100)
    ),
  ),
);

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

とりあえず、キャッシュを生成して試してみます。

コードの内容は、

コントローラー

public function action_memcache()
{
    // 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');

    return Response::forge(View::forge('cache/memcache', $data));
}

View

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

こんな感じです。

この時に使用したLibrary_Testオブジェクトのソースは、

<?php
class Library_Test {
  public static function _init()
  {
  }

  public function __toString()
  {
    return 'Library_Test';
  }

}

こんな感じです。

(Library_Testの設置場所は「fuel/app/classes/library/test.php」です)

でアクセスしてみると、

エラーがでた。memcachedをインストールしてませんでした。

ということでインストール(epelリポジトリなので、もしかすると環境によってはyumのリポジトリが見つからない可能性があります。その場合は、こちらを参考にリポジトリを追加するか、自力でphpのmemcached extensionをインストールしてください)

sudo yum install php-pecl-memcached
sudo /etc/init.d/httpd restart

で、再度アクセス

こんな感じになります。

登録されているキャッシュのデータを確認すると

こんな感じでした。

APCの時と全く同じ形で登録されていました。

問題点

ソースを呼んでみるとphpのmemcachedライブラリの「setOption」を使用が出来るように設計されていません。

となるとデフォルトのままでは「Consistent Hashing」の設定をできないのでは?と思っています。

これができないと「サーバの追加時にキャッシュミスだらけ」になってしまいます。

やっぱり拡張しないとダメなのかな…。

次回は、redisを調べてみます。

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


今回はAPCストレージ

APC

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

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

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

return array(
    'driver' => 'apc',
    'expiration' => null,
    'apc' => array(
        'cache_id'  => 'fuel',
    ),
);

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

とりあえず、キャッシュを生成して試してみます。

コードの内容は、

コントローラー

	public function action_apc()
	{
		// 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');

		return Response::forge(View::forge('cache/apc', $data));
	}

View

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

こんな感じです。

この時に使用したLibrary_Testオブジェクトのソースは

<?php
class Library_Test {
  public static function _init()
  {
  }

  public function __toString()
  {
    return 'Library_Test';
  }

}

こんな感じ

(Library_Testの設置場所は「fuel/app/classes/library/test.php」です)

でアクセスしてみると、

エラーが出た。APCをインストールしていませんでした。

ということでインストール

sudo yum install php-pecl-apc
sudo /etc/init.d/httpd restart

で、再度アクセス

こんな感じになります。

登録されているキャッシュのデータを確認すると

こんな感じで登録されていました。

登録内容的にはFileの時と変わらない感じでした。

次回は、memcachedを調べてみます。

nginxでfuelphpを使用する場合の注意点


 

nginxでfuelphpを使用する時に、「Response::redirect」を使用するとページがただしく表示されない場合があります。

Response::redirect('controller/action');

こんな、感じで普通に記述しても遷移先のURLを見ると

http://hogehoge.com/index.php/controller/index.php/controller/action

こんなURLでNot Foundになってしまいます。

 

こんな時は、

vim app/config/config.php
'base_url' => null,
// これを以下のように修正
'base_url' => '/',

を設定する事で解決できるので、base_urlはnullでなく設定するようにしましょう。

もっと良い解決方法があったら教えて下さい。

[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関数を使用して保存されるもようでした。

return top