2007-11-04 (日)
■ PukiWiki 用プラグイン favicon.inc.php Ver.1.2 を公開
favicon を使って飾り付けをするためのプラグインをバージョンアップした。 前バージョン からの変更点は以下の通り。
- 画像の表示が別プロセスで行われるよう全面的に書き直し
- allow_url_fopen の設定によらず動作するように改良
- PHP 4 でキャッシュ機能が使えなかったのを改良
詳細およびダウンロードは以下のページからどうぞ。
今までは、favicon の処理が全て終わるまでページの表示が待たされてしまっていたが、 今回のバージョンでは、普通の画像ファイルと同じように、 ページを表示した後で favicon が読み込まれるようにした。 これで、表示がスムーズになったはず。
2007-11-07 (水)
■ Zend_Feed と CDATA セクション
先日、Zend_Feed を使って Atom フィードを作成したが、その後でふと感じた疑問。 CDATA セクションの部分って、> などの記号のエスケープって考えなくていいのか?
結論から先に書くと、特に何も考えなくて良いようだ。 (DOM を使わず純粋に文字列としてフィードを組み立てるような場合は、注意が必要。)
この辺を読むと、CDATA セクション内にはどんな文字でもそのまま書けるが、 唯一 ]]> という文字列だけは、
]]> → ]]]]><![CDATA[>
に置換しないといけないことが分かる。
じゃあ、事前にこう置換しておけばいいのか、と思ったが、 試しに ]]> という文字列をそのままつっこんでみたら、 出力されたフィードではちゃんと ]]]]><![CDATA[> に置換されていた。 Zend_Feed の中には、そういう処理をするコードは特に見あたらなかったので、 おそらく DOM 関数の createCDATASection() 辺りで自動的に処理してくれているのだろう。
ということで、とりあえず Zend_Feed を使う場合は、 HTML エスケープとか ]]> の置換とか、そういうややこしいことは考えなくて良いようだ。
2007-11-10 (土)
■ 三角形を示す数値文字参照の一覧
画像ファイルを使わなくても、いろいろな向きの三角形が表示できると分かったのでメモ。
| 数値文字参照 | 記号 |
|---|---|
| ▲ | ▲ |
| △ | △ |
| ► | ► |
| ▼ | ▼ |
| ▽ | ▽ |
| ◄ | ◄ |
ただし、上の表はフォントを指定していないので、ブラウザによっては、► の記号などはつぶれて表示されているはず。
実際に使う時には、font-family: Arial; を指定してやると綺麗に表示される。
以下、tDiary の使い方について余談。 上の記号は、
{{'▲'}}
のように書くことで表示できたが、
font-family を指定する方法を見つけられなかった。たぶん、PukiWiki の style.inc.php プラグインみたいなのを作らないとダメなんだろうな。
{{'<span style="font-family:Arial;">►</span>'}}
でフォントも指定できた。
2007-11-13 (火)
■ YUI Fonts CSS の標準のフォントサイズを変更する方法
Yahoo! UI Library: Fonts CSS を使ってみようとして、変なところではまったのでメモしておく。
YUI Fonts CSS では、フォントサイズは 13px を基準にして % で指定する、というのは知っていたので、 まずは全体を普通の大きさのフォントにしようと思い、以下のように指定してみた。
body {
font-size: 100%;
}
あれれ? なんだか妙に文字が大きい。 font-size: 85%; とか値を小さくしてみると普通のサイズになってきたけれど、 これって、こんな指定をわざわざしないといけないのか?
なにか変だと思い、fonts.css の中身を見てみて、ようやく自分の間違いに気付いた。 fonts.css の中では、
body {font:13px/1.22;*font-size:small;*font:x-small;}
のようにフォントのサイズを設定していた。 つまり自分は、せっかくの fonts.css の設定を上書きしてしまっていたわけだ。
ということで、YUI Fonts CSS を使う場合、body 要素に font-size の指定を書いてはいけません。 (これは、JavaScript を用いたフォントサイズ変更ボタンを設置するような場合でもそう。) だから例えば、全体のフォントを 13px よりも少し大きめにしたいとかいう場合は、
<body> <div id="container"> ... </div> </body>
のような HTML にしておいて、
#container {
font-size: 108%;
}
とかやるんでしょう。
2007-11-15 (木)
■ Safari 3.0.4 for Windows beta がリリース
Mac OS X Leopard 版に引き続き、 Mac OS X Tiger と Windows 版の Safari も新バージョンが出ていた。 変更点は以下の通り。
- Latest security updates
- Improved stability
- Improved compatibility
- Improved JavaScript and application launch performance
- Resize windows from any side
- New keyboard shortcuts
- Additional font smoothing option
- International text input methods
- Advanced text (contextual forms, international scripts)
- NTLM support
- PAC file auto-detection
- FTP directory listings
- Link to proxy settings from Safari (Safari respects the proxy settings in the Windows Internet control panel)
- Cookie management
- LiveConnect support
- Tooltips
- Spell checking
- Printing page numbers, titles, margins
- For detailed information on this update, please visit this website
より詳細な変更点はこちらに書かれている。
2007-11-17 (土)
■ Zend Framework でテンプレートエンジン speedy を 使う
C で書かれた PHP 用テンプレートエンジン speedy が公開されていました。
100%ネタと書かれていますが、ツボを押さえた非常にエレガントなテンプレートエンジンだと思います。 これをネタで終わらせるのはもったいないので、 試しに Zend Framework に組み込んで使えるようにしてみました。
どういうメリットが?
標準の Zend_View では、ビュースクリプトで変数の値を表示しようとする場合、
<?php echo $this->escape($this->variable); ?>
のように書かなければならず、非常に面倒です。 これが speedy を組み込むことで、
<?=h($this->variable)?> <?=h($variable)?>
のように短く書けるようになります。
(追記)
さらに 20071118 版では、
<?p($this->variable)?> <?p($variable)?>
のようにも書けるようになっていました。(2007/11/18)
案1 (Quick Hack)
以下のコードを Revulo/View/Speedy.php として include_path の通ったディレクトリに置きます。
<?php
require_once 'Zend/View/Abstract.php';
class Revulo_View_Speedy extends Zend_View_Abstract
{
protected function _run()
{
// dl('speedy.so');
speedy(func_get_arg(0));
}
}
さらに、ブートストラップの index.php に以下のようなコードを追加して下さい。
require_once 'Revulo/View/Speedy.php';
$view = new Revulo_View_Speedy();
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setView($view);
これで、ビュースクリプト内で、
<?=h($this->variable)?>
のように書けるようになります。
案2
さらに、speedy のテンプレート変数空間の機能を利用してみます。 Revulo/View/Speedy.php を以下のように変更して下さい。
<?php
require_once 'Zend/View/Abstract.php';
class Revulo_View_Speedy extends Zend_View_Abstract
{
private $_vars = array();
public function __set($key, $value)
{
$this->_vars[$key] = $value;
}
public function __get($key)
{
return $this->_vars[$key];
}
public function __isset($key)
{
return isset($this->_vars[$key]);
}
public function __unset($key)
{
unset($this->_vars[$key]);
}
public function assign($spec, $value = null)
{
if (is_array($spec)) {
foreach ($spec as $key => $val) {
$this->_vars[$key] = $val;
}
} else {
$this->_vars[$spec] = $value;
}
}
public function clearVars()
{
$this->_vars = array();
}
protected function _run()
{
// dl('speedy.so');
speedy(func_get_arg(0), $this->_vars);
}
}
これで、
<?=h($variable)?>
のように、より簡潔に書けるようになります。ただし、
<? foreach ($values as $key => $value): ?>
のようにビュースクリプトに書いた場合に、
- assign された変数とループ内のローカル変数との区別がつかなくなる
- $key, $value という変数の実体が $this->_vars['key'], $this->_vars['value'] のようになり、若干速度低下するかも
という点が気になるので、案1のコードの方が使いやすいかもしれません。
2007-11-18 (日)
■ PEAR_ErrorStack のエラーを Exception に変換する
Piece_Flow や Piece_Right などのライブラリは、エラー処理に PEAR_ErrorStack を使っているが、PHP 5 の環境で使う場合には、 どちらかというと例外を投げてくれる方がありがたい気がする。 ということで、PEAR_ErrorStack のエラーを Exception に変換する方法を調べてみた。
この2つを読み比べてみると、 PEAR_ErrorStack クラスは Exception クラスに必要な情報を全て持っているので、 基本的には、PEAR_ErrorStack が渡すデータを元に Exception クラスのインスタンスを作り、 それを throw してやればよい。 ただ、Exception クラスには $file と $line という protected なプロパティがあるが、 このプロパティをいじる方法が Exception クラスには用意されていない。 そこで、
<?php
class Revulo_Exception extends Exception
{
public function __construct($message = null, $code = 0, $file = null, $line = null)
{
parent::__construct($message, $code);
if (isset($file)) {
$this->file = $file;
}
if (isset($line)) {
$this->line = $line;
}
}
public static function handleError($error)
{
if ($error['level'] == 'exception') {
$message = $error['message'];
$code = $error['code'];
$file = $error['context']['file'];
$line = $error['context']['line'];
throw new self($message, $code, $file, $line);
}
}
}
Exception クラスを継承したこういうクラスを作っておいて、
$callback = array('Revulo_Exception', 'handleError');
PEAR_ErrorStack::staticPushCallback($callback);
のようにコールバック関数を指定してやる。 これで、PEAR_ErrorStack の exception レベルのエラーが発生した場合に、 Exception クラスの例外が代わりに throw されるようになる。
2007-11-19 (月)
■ PHP の static メソッドにおいて self, __CLASS__ が示す値
今まで、self とか __CLASS__ というキーワードはそのクラス自身を指すものとばかり思っていたが、 static メソッド内だとそうとは限らないらしい。
<?php
class Base
{
public function __construct()
{
}
public static function foo()
{
return new self();
}
}
class Derived extends Base
{
}
$obj = Derived::foo();
このコードを実行すると、Derived クラスでなく Base クラスのオブジェクトが返ってきた。えーっ!?
(書き直して一般化してありますが、これ、昨日の Exception クラスを継承する話 のコードだったりします。)
調べてみると、これはバグではなく仕様ということらしい。 この不便な仕様は、PHP 5.3 以降の Late Static Binding の機能によって改善されるとのこと。
なお、static メソッドでなければ get_class($this); で Derived というクラス名が得られるようだが、 ここではコンストラクタを呼ぶ前にクラス名が知りたいので、ニワトリと卵のような話になってしまう。 ということで、この問題を回避するために、次のように書き直してみた。
<?php
class Base
{
public function __construct()
{
}
}
class Derived extends Base
{
public static function foo()
{
return new self();
}
}
$obj = Derived::foo();
当たり前だが、こうすれば意図した通り Derived クラスのオブジェクトが返ってくる。 でもなぁ。こうやって全ての子クラスで、同じ内容の foo() メソッドを定義し直すのか? DRY (Don't repeat yourself) に反してるぞ。
2007-11-22 (木)
■ 静的にコールする可能性があるメソッドには static をつける
E_STRICT なエラーになるのはどちらだったか、いつも分からなくなってしまうのでメモ。
static でないメソッドを静的にコールすると、E_STRICT レベルの警告が発生します。
と、てっきりE_STRICTなエラーが発生すると思っていたのに、Strictエラーにならなかったんだっけ。。。?逆はStrictエラーになるけど。
Class::method() のようにインスタンスを作らずに呼ぶ可能性がある場合は、 とにかく static 宣言しておく、と覚えておこう。
2007-11-23 (金)
2007-11-25 (日)
■ Piece Framework のフロー定義ファイルのデフォルト拡張子
久しぶりに Piece Framework を触ってみたら、 フロー定義ファイルのデフォルト拡張子が .flow に変わっていた。 他の箇所では、拡張子とファイルフォーマットが対応しているのに、 なぜここだけその対応が崩れているんだろう。 これ、もしかすると Piece_IDE との絡みなのかな?
ということで、Piece_IDE のマニュアルを見てみる。
フローデザイナーは拡張子がflowのファイルに関連付けられています。
あ、やっぱり、そういう理由か。それなら仕方ない。 こちらでも、フロー定義ファイルの拡張子は .flow というルールでやることにするか。
2007-11-28 (水)
■ PHPTAL 1.1.9 がリリース
PHP 用のテンプレートエンジン PHPTAL が約1年ぶりにバージョンアップしていた。
元々、Python で書かれた Zope Page Templates (ZPT) というのがあって、PHPTAL はそれを PHP に移植したもの。 雰囲気的には、PHP の Flexy や Python の Kid なんかのテンプレートエンジンに似ている。
開発がほぼストップしていて、どうなっちゃうんだろうと思っていたが、 引き継いでくれる人が現れたらしい。良かった。
余裕があれば、 Zend Framework や Piece Framework から使えるようにしてみたいのだけれど、 他にやることがいろいろあるからなぁ。
2007-11-30 (金)
■ Piece Framework のバリデーションテンプレート機能
Piece_Right 1.8.0 以降では、バリデーションテンプレートという機能が追加され、 バリデーションのルールがこんな風に書けるようになった。
- Common.yaml
- name: String
required:
message: %_description% is required
validator:
- name: Length
rule:
min: 1
max: 255
message: The length of %_description% must be less than %max% characters
- Registration.yaml
- name: firstName description: First Name basedOn: String - name: lastName description: Last Name basedOn: String
ここでふと感じた疑問。 String のところに required という条件があるけれど、 これは String フィールドの入力が必須、という意味になってしまったりしないのだろうか? ということで実験をしてみた。
- Common.yaml をテンプレートとして使った場合
- Common.yaml の内容を Registration.yaml にコピーし、1つのバリデーション定義ファイルとして使った場合
それぞれの場合について、getFieldNames() メソッドでフィールド名のリストを見てみると、 1番の場合は firstName と lastName だけだが、 2番の場合は String というフィールドも存在してしまっている。
つまり、バリデーションテンプレートの機能を使いたければ、 その分のルールは、必ず Common.yaml のような別ファイルに保存しておかなければいけないということか。
ついでにもう1つ別の実験。
- name: fullName
description: Full Name
basedOn: String
validator:
- name: Length
rule:
min: 1
max: 1000
message: The length of %_description% must be less than %max% characters
こう書いた場合、テンプレートの Length の条件が上書きされるわけではなく、 Length の条件をもう1つ追加するという意味になるようだ。 つまり、このフィールドに対して 500 文字入力すると、 1〜255 文字というテンプレートの方の条件に引っかかってエラーになる。
