Home > アーカイブ > 2007-11

2007-11

PHPでメールの重要度を設定する

  • 2007-11-03 (土)
  • PHP
この記事の所要時間: 137

システムから配信するメールに重要度を付けたいという話しがあったので調べてみました。

重要度を設定しておくと対応しているMUA(OutlookやらBecky!やら)ではメールの横にマークが付加されます。

分かったことは以下のとおり。

  • 重要度はメールヘッダで設定する。
  • 以前はX-PriorityやらX-MsMail-Priorityやらの独自ヘッダで設定し、MUAでは各々独自に処理していた。
  • RFC1327で重要度を表すPriorityヘッダが用意された。

重要度を設定する値はヘッダによって異なります。

ヘッダ 重要度高 重要度やや高 普通 重要度やや低 重要度低
X-Priotiry 1 2 3 4 5
X-MsMail-Priotiry High Normal Low
Priotiry urgent normal non-urgent

 

PHPでテストしてみました。mb_send_mail()でメールヘッダを設定しているだけです。

<?php
$to = 'hoge@example.com';
$subject = 'subject';
$body = 'body';

// ヘッダで重要度高を設定する
$header = 'Priority: urgent';
//$header = 'X-Priority: 1';
//$header = 'X-MsMail-Priority: High';

mb_language('ja');
mb_send_mail($to, $subject, $body, $header);
?>

このコードを実行すると、手元のBecky!では受信したメールに重要度高が設定されているのが確認できました。

どのヘッダを使用するかですが、Becky!では3つの内、どのヘッダを使用しても重要度が設定されていました。RFC1327で定義されているのは「Priority」なので、今後はこれを利用するのが良いでしょう。(対象のMUAが対応していればですが)

ちなみにBecky!自身で重要度を設定すると「X-Priority」と「X-MsMail-Priority」がヘッダに付加されていました。

今回は管理者向けメールなので受信するMUAが限定できました。様々なMUAに対応する際どのヘッダが対応しているかを調査する必要があるでしょう。

私自身はメールに重要度を設定しないので有用かどうかはあまりピンと来ませんが。:-p

CakePHP 公開する時はデバッグ情報を出さない

この記事の所要時間: 351

CakePHPで作ったシステムを公開する時は、フレームワークが出力するデバッグ情報に気をつけましょう。

1. SQLログ

DEBUG定数の値を2以上に設定すると実行されたSQL文がログとして画面に表示されます。通常本稼働する際はDEBUGを0にしてこの出力は抑制するのですが、たまに本稼働でもSQL文がログが出力されているサイトがあります。

ちなみにSQLログに含まれるキーワードをGoogleで検索すると出力したままのサイトが見つかったりします。

“queries took” “Took (ms)” – Google 検索

対策

[app/config/core.php]にあるDEBUGを0にしておきます。公開サイトでSQL文を確認したい場合はCakePHP SQLをログに記録する方法などを使ってログファイルに出力するのが良いでしょう。

[app/config/core.php]

//	define('DEBUG', 2);
	define('DEBUG', 0);

2. PageControllerへのルーティング

デフォルトのURLルーティングでは[/]と[/pages/*]なURLはPageControllerのdisplayアクションにルーティングされるようになっています。displayアクションでは[/pages/]以降で指定された値をビューテンプレートとして出力します。([/]は/pages/homeとして処理されます)

[/]なURLは大抵アクセスを想定しているのでルーティングを変更すると思うのですが、[/pages/*]なURLは変更を忘れがちです。そのままだと[/pages/home]なURLを指定すると、フレームワークに含まれるhome.thtmlが出力されてしまいます。

http://example.com/pages/home

対策

[app/config/routes.php]にあるPageControllerへのルーティングを削除します。

[app/config/routes.php]

// [/]のURLルーティングを変更
//	$Route->connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
	$Route->connect('/', array('controller' => 'top', 'action' => 'index'));
(snip)
// [/pages/*]のURLルーティングを変更
//	$Route->connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));

3. 存在しないコントローラ、アクション

これもDEBUG定数の値によって出力されます。DEBUGの値が1以上の場合、存在しないコントローラやアクションがURLで指定されるとエラーメッセージが表示されてしまいます。

例えばそこで[/a/a]のように存在しないであろうコントローラやアクションを指定すると「Missing Controller」や「Missing Method」が表示されます。

対策

1.と同様にDEBUGの値を0にします。

対策-さらに

フレームワークは[/foo(/bar)?]なURLであればコントローラとアクション(/barがなければ/indexが存在するとみなす)を探そうとします。ですのでリバースプロキシなどで外部からCakePHPシステムへアクセスされるURLを限定してしまうのもアリです。

こうしておけば予期せぬURLからのアクセスを防ぐことができるので、URLルーティングにおける想定外の動作を防ぐことができます。(この手法は結構好きなので良く使用します。;-))

便利機能には注意を

CakePHPに限らず各種フレームワークには開発に有用なデバッグ情報出力などの機能が用意されています。これらの情報は開発には役立ちますが、一般に公開すると攻撃者へヒントを与えることにもなりますし、何より見た目が宜しくありません。

特にURLルーティングに関しては今時のフレームワークでは実装されている機能だと思います。外部に公開するシステムでは、あらかじめ想定外のURLが指定された場合、どのような動作をするかを確認しておきましょう。

PostgreSQL VACUUM FULLせずに不要領域を削除する

この記事の所要時間: 41

PostgreSQLではDELETEしたレコードは物理的には削除されずそのまま残り続けます。テーブル自体のサイズ(容量)を削減するにはDELETEした後にVACUUM FULLを行う必要があります。

このVACUUM FULLはテーブルへの書き込みロックがかかります。また数GクラスのテーブルへのVACUUM FULLは数時間かかることがあるので、常時書き込みがあるテーブルへは処理を行うタイミングが難しいです。

そこでVACUUM FULLを行わずに不要領域を削除(テーブルサイズを減らす)する方法を考えました。

方法は単純で「テーブルを新たに作って、そちらにデータを移行する」だけです。流れとしては以下のようになります。

  1. 不要領域を削除するテーブル(移行元テーブル)と同じレイアウトのテーブルを作成する(移行先テーブル)
  2. 移行先テーブルにレコードを移行する
  3. 移行先テーブルにインデックスを設定する
  4. 移行元テーブル名を変更する
  5. 移行先テーブル名を移行元テーブル名に変更する

ここでは不要領域を削除するテーブル(移行元)をitems、移行先をitems_newとします。

1. items_newテーブルを作る

create table as文でitems_newテーブルを作成します。「limit 0」を指定することによりレコードを移行することなくitemsと同じレイアウトのテーブルを生成します。但しこの方法では制約等は受け継がれないので別途作成する必要があります。

create table items_new as select * from items limit 0;

2. レコードを移行する

insert into select文でitemsテーブルからitems_newテーブルにレコードを格納します。ポイントは全レコードを一度に移す必要が無く、select文のwhere句で条件を指定して序々に移行することができる点です。ログのような時系列で並ぶレコードでは一度登録されたレコードを変更されることが無いので、この方法で少しづつ移行することができます。

逆に各レコードがランダムに変更されるようなテーブルだとこのアプローチは使えません。

order by句を指定することにより任意の順序でレコードを格納することができます。

insert into items_new select * from items where created between '2007/1/1 00:00:00' and '2007/1/31 23:59:59' order by created;

3. items_newテーブルにインデックスを設定する

items_newテーブルにインデックスを設定します。インデックス設定はロックがかかるのでこの段階で行います。

create index items_new on ...;

● itemsテーブルへの書き込みを停止する

常時itemsテーブルへの書き込みがある場合は、このタイミングで書き込みを一旦停止します。停止の方法には、サービスを一時停止する、テンポラリテーブルに書き出す、ファイルに書き出す等が考えられます。

4. itemsテーブルのテーブル名を変更する

itemsテーブルのテーブル名を適当な名前に変更します。

alter table items rename to items_old;

5. itemsテーブルのテーブル名を変更する

items_newテーブルのテーブル名をitemsに変更します。

alter table items_new rename to items;

● itemsテーブルへの書き込みを再開する

itemsテーブルへの書き込みを再開して完了です。もし停止期間に書き込むデータがあればitemsに書き戻します。またこの方法では外部制約は設定していないので、もしitemsやそれに関連するテーブルに外部参照制約があるならそちらも設定します。(そもそも外部参照がからむようなテーブルにはこの方法自体が不向きですね。)

VACUUM FULLは意外とやっかい

テーブルサイズが巨大化するとVACUUM FULLは意外とヘビーです。通常はコンカレントVACUUMで用が済むかもしれませんが、テーブルサイズを小さくしたい場合などは、今回のようにちょっとした工夫が必要となります。

ちなみにこの方法を取ると当然ながらレコードのoidが変わります。oidに依存しているシステムでは適用できませんのでご注意を。

Home > アーカイブ > 2007-11

検索
フィード
メタ情報

Return to page top