第3回 CakePHP 勉強会で時間の都合から言えなかったことがありました。 assert() 関数には式を渡すのではなく文字列を渡して使うのが正解です。
assert($arg != 0); // 誤り!
assert('$arg != 0'); // OK
どちらの記述も一見すると正しく動いているように見えるのですが、式が成立しないときのエラーメッセージが変わります。前者は失敗したことしかわかりませんが、後者はどの式に失敗したのかがわかります。
ながらく C/C++ のプリプロセッサという超法規的措置の assert を使っていた人は要注意です。
IE で Ajax リクエストをキャッシュさせないようにするためには、次のいずれかの手段をとります。
- post 通信にする
- リクエスト URL に一意なクエリストリングを付加する
- If-Modified-Since ヘッダを送出する
個人的には2番目の手段が好きです。 new Date() で済みますので。
今日知ったのですが PHP の疑似乱数生成にはメルセンヌツイスタが使えるそうです。
その名も mt_rand() 。
マニュアルによると古いバージョンの PHP でも使えるようですが、本当でしょうか。というか、このあたりの心配を払拭するためにも PHP5 へ移行したい気持ちでいっぱいです。
ちなみにメルセンヌツイスタは普通の rand() と違って、再現する乱数にはなりません。
頭の痛い壊れた UTF-8 の検証問題ですが、ネットでこんなコードを見つけました。
<?php
function check($check)
{
$sjis = mb_convert_encoding($check, "SJIS-win", "UTF-8");
$utf8 = mb_convert_encoding($sjis , "UTF-8" , "SJIS-win");
return ($check === $utf8);
}
?>
なんてわかりやすいんでしょうか。しかし、正しく機能するのか謎です。ちょっと試してみた限りではかなりの精度で誤りを検出できるようです。
実は、現在開発中のシステムがいろんな言語を扱う予定があるため UNICODE を使いたいのです。発想が非日本人っぽくて自己嫌悪してしまいそうですが、引き続き書籍などからヒントを得てみようと思います。
何か良い方法がわかり次第レポートいたします。
Ajax ヘルパーを使うとビューテンプレートからイベントハンドラを設定可能となり、ある程度 CakePHP が JavaScript の記述量を吸収してくれるのですが、コールバック関数は自分で書く必要があります。
このとき、イベントの情報がコールバック関数の引数として渡ってくるのですが、この参照が指すオブジェクトの仕様がブラウザによって違うので振り分けが非常に面倒です。
これを解決するためには prototype.js の Event.element() メソッドを使います。
function callbackFunction(e)
{
var element = Event.element(e);
}
というか、ほぼ IE 向けの対策なのですが、 IE の仕様をベースに策定したイベントモデルがなぜ IE でのみ違う振る舞いをするのか謎が深まります。
バッチスクリプトやファイルアップロードといった重い処理を実行する際に設定する php.ini ディレクティブをまとめてみました。
| ディレクティブ |
意味 |
初期値 |
設定場所 |
| upload_max_filesize |
アップロードするファイルサイズの最大値 |
“2M” |
PHP_INI_PERDIR PHP_INI_ALL(PHP <= 4.2.3) |
| post_max_size |
POST データサイズの最大値 |
“8M” |
PHP_INI_PERDIR PHP_INI_SYSTEM ( PHP <= 4.2.3 ) |
| memory_limit |
スクリプトが確保できるメモリサイズの最大値 |
“128M” |
PHP_INI_ALL |
| max_execution_time |
スクリプトが強制終了させられるまでの秒数 |
“30″ |
PHP_INI_ALL |
なお、これらの設定値は次の関係が成り立つように設定する必要があります。
upload_max_filesize <post_max_size <memory_limit
CakePHP 1.2 から Oracle を利用する際の情報がいくつかあるようです。
CakePHP_Oracle.ppt :: handsOut.jp
フィブログ CakePHPからOracleに接続する方法
Using Oracle with CakePHP: 15 Minute Blog Tutorial & William Graham’s blog
私が感じた注意点は次のような部分です。
- Oracle には MySQL のような AUTO_INCREMENT がないので id はシーケンスとトリガーで自動採番する
- database.php の driver には oracle を指定する
- database.php の connect には oci_connect を指定する
冒頭のサイトの情報によると CakePHP 1.2 + Oracle では DELETE がうまく動作しないらしいのですが、少し古い MySQL でも DELETE は動作しません。おそらく DELETE 文にエイリアスを書いていることが原因かと思われるのですが、とりあえず Model::beforeDelete() 中で Model::query() 等を使って直に DELETE を実行すれば対応できます。
Oracle のインストール方法に関してはこちらを参照ください。
CentOS へ Oracle10gXE をインストールするためには、次の手順を踏みます。
Oracle 10g XE のダウンロード
次のサイトから Oracle10gXE の RPM パッケージをダウンロードします。ダウンロードの際には oracle.com のアカウントが必要です。
ORACLE Technology NETWORK
libaio のインストール
Oracle10gXE をインストールするために必要な libaio を追加インストールします。
Oracle 10g XE のインストール
ダウンロードした RPM パッケージから Oracle10gXE をインストールします。
# rpm -ivh oracle-xe-univ-10.2.0.1-1.0.i386.rpm
Preparing... ########################################### [100%]
1:oracle-xe-univ ########################################### [100%]
Executing Post-install steps...
You must run '/etc/init.d/oracle-xe configure' as the root user to
configure the database.
上記メッセージに従って、 /etc/init.d/oracle-xe configure を実行します。
# /etc/init.d/oracle-xe configure
Oracle Database 10g Express Edition Configuration
-------------------------------------------------
This will configure on-boot properties of Oracle Database 10g Express
Edition. The following questions will determine whether the database should
be starting upon system boot, the ports it will use, and the passwords that
will be used for database accounts. Press <Enter> to accept the defaults.
Ctrl-C will abort.
Specify the HTTP port that will be used for Oracle Application Express [8080]:
Specify a port that will be used for the database listener [1521]:
Specify a password to be used for database accounts. Note that the same
password will be used for SYS and SYSTEM. Oracle recommends the use of
different passwords for each database account. This can be done after
initial configuration:
Confirm the password:
Do you want Oracle Database 10g Express Edition to be started on boot (y/n) [y]:
HTTP ポート、リスナーポート、パスワード、 boot 時にoracle XE 起動するかどうかを対話式に設定していきます。
Specify the HTTP port that will be used for Oracle Application Express [8080]:
.
Oracle Application Express へのアクセスポートを設定します。デフォルトの 8080 で問題ない場合はそのまま Enter を押します。
Specify a port that will be used for the database listener [1521]:
.
データベースのリスナーポートを設定します。デフォルトの 1521 で問題ない場合はそのまま Enter を押します。
initial configuration:
Confirm the password:
システム管理者である SYS と SYSTEM のパスワードを設定します。確認のため、2回、同じパスワードを入力します。
Do you want Oracle Database 10g Express Edition to be started on boot (y/n) [y]:
.
システムのブート時に Oracle を開始するかを設定します。システムのブートとともに開始して問題ない場合は Enter を押します。
インストール時に追加された oracle ユーザに bash 関連ファイル付与
インストール時に追加された oracle ユーザにシェル環境を与えるため、スケルトンの設定ファイルをコピーします。
# su - oracle
$ cp /etc/skel/.bash* /usr/lib/oracle/xe/
SQL*Plus をフルパスで呼び出しさないで済む設定を各ユーザアカウントに追加
該当アカウントホームディレクトリに移動後…
$ vi .bash_profile
$ vi /usr/lib/oracle/xe/.bash_profile
.bash_profile ファイルに次の行を追記する。
# ファイルの末尾
. /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh
以上です。
CakePHP 1.2 から Oracle を使う場合はこちらも参照ください。
過去の IE での動作検証に役立ちそうなソフトウェアを見つけました。
IE5.5, IE6, IE7, IE8の確認が同時にできる -IETester
この記事によると IETester をインストールすることによって、任意のバージョンのレンダリングエンジンを選択して Web サイトを表示することができるとのことです。スタンドアロンで動作する上に、既存の IE の環境を壊したりすることはないようです。
IE8 もターゲットになっている点に驚きます。
それにしても、こういうソフトが作れると言うことは、 IE のレンダリングエンジンは QueryInterface() で過去のバージョンが取ってこれるということなのでしょうか。
フレームワークを使っていると足下がおろそかになってしまいそうな心配がぬぐえません(本当はフレームワークのせいではなくスキルの未熟さから来ているのでしょうが)。
今回はメール送信を通じて日本語を扱う際の設定を見直してみました。
PHP で日本語を扱う際には mbstring 関連のディレクティブを設定することになりますが。大抵は次のような設定になると思います。
mbstring.language = Japanese
mbstring.internal_encoding = EUC-JP
名前から察するに mbstring.language によって mbstring 関連の関数が日本語に初期化され、 mbstring.internal_encoding によって mbstring 関連の関数が内部で利用する文字コードが決定されると思ってしまいがちですが、これが大きな誤解で、 mbstring.language は mb_send_mail() が送信の際に参考にする言語で、 mbstring.internal_encoding は mbstring 系の関数のデフォルトのエンコーディング程度の意味しかないとのことです。
幸い、この程度であれば誤解のまま運用し続けても大きな問題は起こらないかもしれませんが、 mbstring.internal_encoding という名前から PHP も Java のように「内部エンコーディング」があると勘違いしてしまうと、出所のわからないバグに遭遇してしまうかもしれません。 PHP が扱っている(マルチバイト)の文字列も所詮はただのバイト列という再認識が必要かと思われます。
今回得た知識を利用した関数が次のコードです。パソコン向けに添付ファイルを同梱しないメールを送るという用途には十分かと思われますが、おそらく PHPMailer の利用を検討した方が賢明です。
<?php
http://phpmailer.codeworxtech.com/http://techblog.ecstudio.jp/tech-tips/mail-japanese-advance.html @access @param @param @param @param @param @param @param @return function btaSendMailByJapanese($to, $subject, $body,
$from = null, $fromName = null,
$returnPath = null,
$encoding = null)
{
assert('function_exists("mb_send_mail")');
{
$previousLanguage = ini_get("mbstring.language");
$previousEncoding = ini_get("mbstring.internal_encoding");
$previousWinFrom = ini_get("sendmail_from");
}
{
mb_language("Japanese");
if (!is_null($encoding)) {
mb_internal_encoding($encoding);
}
}
$header = "";
{
$headers = array();
if (!empty($from)) {
if (!empty($fromName)) {
$fromNameEncoding = mb_detect_encoding($fromName);
$fromName = mb_convert_encoding($fromName, "JIS", $fromNameEncoding);
$fromName = mb_encode_mimeheader($fromName);
array_push($headers, sprintf("From:%s <%s>", $fromName, $from));
} else {
array_push($headers, sprintf("From:%s", $from));
}
}
if (count($headers) == 0) {
array_push($headers, "X-PlaceHolder:placeholder");
}
$header = join("\r\n", $headers);
}
$mtaOption = "";
{
if (!empty($returnPath)) {
$mtaOption = "-f ". $returnPath;
ini_set("sendmail_from", $from);
}
}
$result = mb_send_mail($to, $subject, $body, $header, $mtaOption);
{
ini_set("mbstring.language", $previousLanguage);
ini_set("mbstring.internal_encoding", $previousEncoding);
ini_set("sendmail_from", $previousWinFrom);
}
return $result;
}
?>