CakePHP Authコンポーネントでユーザー情報とセッションの更新

ログインの処理はAuthコンポーネントを使用する事が多いと思います。
Authコンポーネントを使用すると、ユーザー情報はセッションに保存されますが、認証に使うテーブル(デフォルトUsers)を更新した場合は保存されているセッションは更新されないので以下のようにします。

$this->User->save($data);
$this->Auth->login($this->Auth->user('id'));

こうすると、セッションも更新されます。

http://api13.cakephp.org/class/auth-component#method-AuthComponentlogin

MySQLのキャッシュサイズ変更で重いSQLを高速化

MySQLパフォーマンスチューニングのためのクエリの基礎知識
パフォーマンスチューニングについては↑が非常に参考になります。

ただ、いくらパフォーマンスチューニングをしてもMySQLの設定がデフォルトでは限界が有るので、設定も変更する必要が有ります。

InnoDBをメインストレージエンジンとしている場合は、

innodb_buffer_pool_size
 ⇒InnoDBのインデックスやレコードをキャッシュするメモリ領域のサイズ

innodb_log_file_size
 ⇒InnoDBの更新ログを記録するディスク上のファイルサイズ
 ⇒innodb_buffer_pool_sizeのサイズを増やしたらinnodb_log_file_sizeも合わせて調整する必要が有る。

が重要。

SHOW VARIABLESコマンドで現状の設定をまず確認。

mysql > SHOW VARIABLES LIKE "innodb_%_size";
+---------------------------------+---------+
| Variable_name                   | Value   |
+---------------------------------+---------+
| innodb_additional_mem_pool_size | 1048576 |
| innodb_buffer_pool_size         | 8388608 |
| innodb_log_buffer_size          | 1048576 |
| innodb_log_file_size            | 5242880 |
+---------------------------------+---------+
4 rows in set (0.00 sec)

innodb_buffer_pool_sizeはデフォルトでは8Mに割り当てられています。
変更するにはWindowsの場合はmy.ini、Linux系の場合はmy.cnfを編集します。

innodb_buffer_pool_size = 16M
innodb_log_file_size = 2M

MySQLを再起動して、確認。

mysql > SHOW VARIABLES LIKE "innodb_%_size";
+---------------------------------+----------+
| Variable_name                   | Value    |
+---------------------------------+----------+
| innodb_additional_mem_pool_size | 1048576  |
| innodb_buffer_pool_size         | 16777216 |
| innodb_log_buffer_size          | 1048576  |
| innodb_log_file_size            | 2097152  |
+---------------------------------+----------+
4 rows in set (0.00 sec)

開発環境ではデフォルトの設定で開発していたので、本番環境からデータを取ってくるとSQLが重すぎる!ってことがありましたが、これで解消されました。

[参考にさせて頂いたサイト]
5分でできる、MySQLのメモリ関係のチューニング!
MySQL 初めてのチューニング

Windows7でmy.iniの編集について

my.iniをsakuraエディタで変更して、再起動しても全然設定が反映されない・・・。

何の事は無い、管理者権限で開いたら設定が変更できました。

設定変更したら、確認はしないと駄目ですね。

今回設定変更した箇所

# Set the SQL mode to strict
#sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

確認方法はコンソールから

SELECT @@sql_mode;

MySQLの削除について

Windows7でMySQLをアンインストールするとゴミデータとサービスがそのまま残った状態になってしまう(サービスに登録している場合)。
データは手動で削除出来るが、サービスは以下の方法で削除できる。

sc delete mysql

※mysqlという名前でサービスが登録されていた場合

Windows7、Vistaの場合は管理者権限でコマンドプロンプトを起動しないと「アクセスを拒否されました」となってしまうので注意。

CakePHPのSecurity.levelまとめ

まずは、Security.levelについて

Security.level session.cookie_lifetime(セッションクッキーの有効期間) session.referer_check SESSION IS
high 0(ブラウザを閉じるまで) $_SERVER[“HTTP_HOST”]; リクエストごとに作成される
medium 7日間 $_SERVER[“HTTP_HOST”];
low 25年間 なし

session.cookie_lifetimeはセッションクッキーの有効期間なので、セッションタイムアウトは別に[core.php]の

/**
 * 'high'	Session timeout in 'Session.timeout' x 10
 * 'medium'	Session timeout in 'Session.timeout' x 100
 * 'low'		Session timeout in 'Session.timeout' x 300
 */
Configure::write('Session.timeout', '120');

で指定する。(Security.levelの設定によって変わる)

また、session.cookie_lifetimeの値はCakePHP 1.3 のもので、1.3.5だと

if ($this->security == 'high') {
	$this->cookieLifeTime = 0;
} else {
	$this->cookieLifeTime = Configure::read('Session.timeout') * (Security::inactiveMins() * 60);
}

Security::inactiveMins()は

function inactiveMins() {
	switch (Configure::read('Security.level')) {
		case 'high':
			return 10;
		break;
		case 'medium':
			return 100;
		break;
		case 'low':
		default:
			return 300;
			break;
	}
}

なので、Session.timeoutに依存する。(デフォルトは120m)

session.referer_checkとは

session.referer_check には、HTTP Referer に おいて確認を行う文字列を指定します。Refererがクライアントにより 送信されており、かつ、指定した文字列が見付からない場合、埋め込 まれたセッションIDは無効となります。デフォルトは空の文字列です。 

セッションハイジャックとかを防止するためには必要だと思う。

どうしたいか

  • ブラウザ閉じたらセッションは削除したい(自動ログインの機能は別途作成)
  • session.referer_checkできれば有効にする

ブラウザ閉じたらセッションは削除したい(自動ログインの機能は別途作成)

Security.level = ‘high’ だと リクエストごとにSESSION ID が作られるので、それだと携帯サイトの場合、都合が悪い、SESSION IDはそのままで、ブラウザ閉じたらセッションは削除したい。

/app/config/my_session.phpという設定ファイルを作成し、[core.php]に設定する。

Configure::write('Session.save', 'my_session');

my_session.phpは[cake_session.php]のcase ‘cake’:をコピーして

if (empty($_SESSION)) {
	if ($iniSet) {
		ini_set('session.use_trans_sid', 0);
		ini_set('url_rewriter.tags', '');
		ini_set('session.serialize_handler', 'php');
		ini_set('session.use_cookies', 1);
		ini_set('session.name', Configure::read('Session.cookie'));
		//ini_set('session.cookie_lifetime', $this->cookieLifeTime);
		ini_set('session.cookie_lifetime', 0); // 変更
		ini_set('session.cookie_path', $this->path);
		ini_set('session.auto_start', 0);
		ini_set('session.save_path', TMP . 'sessions');
	}
}

session.cookie_lifetimeを’0’にして、ブラウザが閉じたらセッションを削除するようにする。

session.referer_checkできれば有効にする

Security.level は ’high’ or ‘medium’ にする。
このチェックに引っ掛かるとセッションが消えてしまうので、WEBサービス何かと連携する時は’low’にした方が無難。
※proxyを使っててもリファラーチェックに引っ掛かる事が有った。

ただ、セッションが切れないように作り方を変えれば良い場合も有るので、なるべくそっちで対応した方が良い。

最後に

今回は
仮登録メール⇒メールに記載のURLクリック⇒(内部でリダイレクトして)プロフィールフォーム⇒登録完了
という機能を作成していて、開発時のメールサーバーはRadishを使っていたので、問題無かったが本番にリリースした際(yahooメール等)、セッションが切れて登録出来ないという不具合が起きてしまった。
その為、リダイレクトの必要は特に無かったので、リダイレクトをしないようにして事なきを得た。
しかし、本番でもテストはしていたのだが、リリースしたのが結構前だった為、この現象が起きたかどうか覚えていない。
※普通にURLをコピーしてアドレスバーに貼り付けてテストしたのかも・・・

色々ありましたが、勉強になりました。

Host名の変更

ホスト名登録

vi /etc/sysconfig/network

HOSTNAME="example.com"          ←追記

サーバー再起動。
※Servermansのコントロールパネルから[停止]と[起動]

自ホストの正引きアドレス変更

vi /etc/hosts

127.0.0.1 localhost.localdomain localhost              →修正前
127.0.0.1 localhost.localdomain localhost example.com  →修正後

SSHポート変更

SSHポート変更しますよってServermansからメールが来てたので変更される前に変更する。

しかし、久々に自分のサーバー触ってみたらかってが分からず30分くらいあたふた・・・

①suusuke.infoで名前解決できなくなってた
 →これは自分で変更してたの忘れてた・・・
②MySQLが起動してない
 →Why?まあいいや。

って事が有りましたので備忘録かねて設定変更手順を記述

デフォルトで22番ポートになっているので任意に変更
※rootもしくはsudoを使って作業

vi /etc/ssh/sshd_config

#Port 22
Port xxxx

再起動

/etc/rc.d/init.d/sshd restart
Stopping sshd:                                             [  OK  ]
Starting sshd:                                             [  OK  ]

後はmacのsshクライアントの設定も変更しておく

vi ~/.ssh/config

Host suusuke.info
    HostName suusuke.info
    Port xxxx
    User suusuke
    IdentityFile ~/ssh/xxxxx/id_rsa_putty_openssh.ppk
    ServerAliveInterval 60

ssh suusuke.info で接続確認して終了。

Postfixでメールサーバー設定

root宛てのメールをgmailに転送して読めるようにする。

Postfixインストール

yumでインストールする。
※rootもしくはsudoで作業する

yum install postfix

Postfixの設定

main.cfの設定


#取得したドメイン名(DNSで名前解決できるホスト名)
#myhostname = host.domain.tld
#myhostname = virtual.domain.tld
myhostname = example.net


#ドメイン名
#mydomain = domain.tld
mydomain = example.com


# メール送信の設定
# メールの送信元を示す
#myorigin = $myhostname
#myorigin = $mydomain
myorigin = $myhostname


#メール受信の設定
#メールを受け取る範囲を指定する。内部からのみ許可。
#inet_interfaces = all
#inet_interfaces = $myhostname
#inet_interfaces = localhost
inet_interfaces = $myhostname, localhost


#自ホストが最終目的地であるドメイン名
#mydestination = $myhostname, localhost.$mydomain, localhost
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
#       mail.$mydomain, www.$mydomain, ftp.$mydomain
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain


#メールBOXの形式を指定
#home_mailbox = Mailbox
home_mailbox = Maildir/

※メールBOXの形式についてはこちらが参考になりました。

転送設定

	
vi /etc/aliases

# Person who should get root's mail
#root:          marc
#転送先のメールアドレスを指定
root:           example_xxxx@gmail.com

設定を反映させる。

newaliases

サービスを起動する。

/etc/init.d/postfix start

自動起動をonにする。

	
chkconfig postfix on

テスト

testメールを送ってみる。

mail -s "Subject:test-mail" root

Enterを押して、本文を入力

これはテストメールです。
→Ctrl-Dを押す
Cc:
→Enterを押す

gmailにメールが転送されていれば完了。

PHPのarray_mergeは良い

array_margeは便利だと思う。

$attributes = array(
    'var1' => 'aaa',
    'var3' => 'bbb',
);
$defaults = array(
    'var1' => null,
    'var2' => null,
    'var3' => '-',
    'var4' => '-',
    'var5' => '-',
);
$attributes = array_merge($defaults, $attributes);

echo '<PRE>';
print_r($attributes);
echo '</PRE>';

実行結果↓

Array
(
    [var1] => aaa
    [var2] => 
    [var3] => bbb
    [var4] => -
    [var5] => -
)

配列にデフォルト設定するとき良く使う。

ちなみに、配列のキーの差分を取得するarray_diff_keyも便利です。

$attributes = array(
    'var1' => 'aaa',
    'var3' => 'bbb',
    'var6' => 'ccc',
);
$defaults = array(
    'var1' => null,
    'var2' => null,
    'var3' => '-',
    'var4' => '-',
    'var5' => '-',
);

$attributes = array_diff_key($attributes, $defaults);

echo '<PRE>';
print_r($attributes);
echo '</PRE>';

実行結果↓

Array
(
    [var6] => ccc
)

PHPを使い始めてそろそろ1年・・・

GETパラメーターでURLを送りたい

普通に

<a href="/xxx/?url=http://aaa.com/">リンク</a>

で良いんだけど渡したいURLの中にさらにパラメーターが複数ある場合

<a href="/xxx/?url=http://aaa.com/?id=1&var=2">リンク</a>

こうすると

url = http://aaa.com/?id=1
var = 2

みたいになってしまうので

<a href="/xxx/?url=http://aaa.com/?id=1%26var=2">リンク</a>

とすると良いよ。