March 2006

Entries Title

MySQL 5 の 64bit 版は、PHP 5 の mysqli の構築に失敗する

Date
2006-03-30 (Thu)
Category
Tech

前回に引き続き、Tiger に環境を再構築中。PHP と MySQL をインストールします。

まず、Tiger 自身についてくる PHP をアンインストールしましょう。というか整理してとっておきますが。僕がまとめたファイルとしては、

  • /usr/lib/php
  • /usr/include/php
  • /usr/bin/php*

の三カ所。/usr/bin/には、

  • php
  • php-config
  • phpextdist
  • phpize

という4つのコマンドラインが入ってますので、mv /usr/bin/php* /path/to/somewhere/ とかしてどけましょう。

MySQL は、インストール自体は簡単。MySQL Downloads から自分の環境にあったものを入れればいいだけ!といいたいところですが、表題の通り、PowerMac G5 では、MySQL 5.0 の 64bit 版を入れておくと、PHP 5 の mysqli の構築に失敗します。

なぜか?よくわかりません。出るエラーは "configure: error: wrong mysql library version or lib not found" です。MySQL Improved Extension の User Contribute Note にいくつか例が出てますが、それとも違うみたい。同じ状況としては、

MySQL Bugs: #15916: PHP configure failed with MySQLi library error.

かな。OS は違うけど、CPU は一緒だし、出てるエラーの出方もそっくり。で、これは解決されてない。ので、どうしたかというと、MySQL 5.0.19 - Max - Mac OS X 10.4(PowerPC) をインストールしたのでした。ま、64 bit だからどうだという性能差は僕の環境では使わないでしょうし。

最後にようやく PHP の設定。とりあえず最初に入ってる状況からは余りかえず、libxml2 だけ入れて、あとはシンプルに。以下 configuration オプション。

--with-apxs \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--sysconfdir=/private/etc \
--enable-mbstring=all \
--enable-mbregex \
--enable-exif \
--with-libxml-dir=/usr/local/lib \
--with-xmlrpc \
--with-zlib-dir=/usr \
--enable-trans-sid \
--enable-sockets \
--with-xml \
--with-iodbc=/usr \
--with-curl=/usr \
--with-config-file-path=/etc \
--with-mysqli=/usr/local/mysql/bin/mysql_config


そうだ。Developer Tools をインストールした時に、思いあまって WebObjects もインストールしました。すると、デフォルトバックエンドとして、OpenBase がセットアップされて毎回起動します。それはウザイけど止める方法は書いてない、と。単純に、/Library/StartupItems/OpenBase というディレクトリを、消せば止まります。僕はディレクトリ名の頭に . (dot) をつけて、不可視にしましたが。

Tiger と週末

Date
2006-03-30 (Thu)
Category
Tech

前々から調子の悪かった、PowerMac G5 なんですが、ついに先週末再起動不能になりまして、先週末は再起のためにすべての時間を費やしたといっても過言ではありませんでした。。壊れたのは標準搭載 Graphics card の ATI Radeon 9600 Pro(64MB)。加えて前から壊れていた内蔵 Optical drive の Pioneer DVR-106PB も交換することに。

使っているモニタが Apple Studio Display 17 inch なので、ADC(Apple Display Connector)しかついていません。。当初の予定では、今回はとりあえず SuperDrive だけ取り替えて、バックアップをとって、その場を凌ぐつもりが、結局起動しなくなって、Graphics Card も…みたいな流れで。。まぁ急に思い立って買った割にはずいぶん安くついたのでよしとしましょうシクシク。

ついでに Tiger にアップデートしたのはいいけれど…モニタカード入れ替えたところで、バックアップ作業をすればいいものを、なんか下手に ATI の Graphics Card driver を入れたりアップデートしたりしていたら、、、Panther が再起不能な(というか ATI driver tool しか立ち上がらない!)状況に陥り、ここ数年で初めて、データ消失をやらかしました。おかげで、未だに完全復旧にはいたっていません。。。

今回の散財

  • ATI Radeon 9800 256MB
  • Apple DVI-ADC connector
  • Pioneer DVR-110

“var is” はまだ使える。

Date
2006-03-23 (Thu)
Category
javascript

slashdot のIE7はWindows Explorerと分離へを読んで、この間 var isなんてエントリを書いたばっかりだけど、使えなくなんのかよ!と焦った。

Internet Explorer との互換性向上
サイト互換性のため、判別を含まない document.all サポートが追加されました。また、キーボードアクセラレータの互換性を改善したことで、Internet Explorer ユーザがよりスムーズに移行できるようになりました。
Mozilla Firefox Preview Release (Greenlane) リリースノート

しかりよく見たらリリースノート古いしさ。焦ってググリまくったら、すご〜い古い話題だと気がついた。全ての正解は以下。

【DOCTYPE指定のXHTML文書】
 document.all      = undefine
 document.layers     = undefine
 if(document.all)    = false
 if(document.layers)   = false

【DOCTYPE指定なしHTML文書=quirks モード】
 document.all           = [object HTML document.all class]
 document.layers          = undefine
 if(document.all)         = false
 if(document.all('IDname'))    = true
 if(document.layers)        = false
 document.all("idname")      = [object HTML DivElement]
 document.all("idname").offsetTop = 正しい値
  
 document.allを使用すると、以下の警告がJavaScriptコンソールに出ます。
   →Warning: Non-standard document.all property was used.
         Use W3C standard document.getElementById() instead.
Mozのdocument.allサポート経由で見つけたMozilla が何と doument.all をサポートした!!

つまり standard 準拠モードなら var is は使える、と言うことですね。

検証するには、例えば

以下の bookmarklet をこのページで使うと、(IE 以外では)エラーが出ます。

document.all('container')

でも google のトップページに行って

document.all('1a')
document.getElementById('1a')

同じダイアログが現れたのではないでしょうか。ちょっと焦ったけど、ウラ取りが大事な世界に僕らは居るんだなと感じた今日この頃でした。

Dreamhost で PEAR ローカルコピーを作る

Date
2006-03-18 (Sat)
Category
php

前のエントリの続きです。)PEAR のローカルコピー、つまり展開先を指定して PEAR のファイルをとってくる方法を解説します。Dreamhost と唱っていますが、Terminal アクセス(ssh)のあるレンタルホストならどこでも同じように出来ると思います。

前々から、何処かで記事を書いた気がする、と思っていたけれど、この blog 内には見当たらないし。ま、実際書くほども無い位簡単ではある。しかし、今回、この サイトのある dreamhost で試してみたら…

> pear -s -c ~/.pearrc -d doc_dir=~/pear/docs -d ext_dir=~/pear/ext \
       -d php_dir=~/pear/lib -d data_dir=~/pear/data -d test_dir=~/pear/tests \
       -d cache_dir=~/pear/cache -d bin_dir=~/pear/bin
> pear -c ~/.pearrc install Archive_Tar
WARNING: channel "pear.php.net" has updated its protocols, use "channel-update pear.php.net" to update
Cannot install, php_dir for channel "pear.php.net" is not writeable by the current user

と出てうまく行かない…ググって見つけたのが此のサイト。

さくらサーバで PEAR を自由に使いたい場合

…此れ書いたの自分じゃん。。(微妙に間違ったことも書いてる気がするが、まぁいいや。)

どっちにしても、共有ホストにおける PEAR のローカルコピーのインストール をリンクしていて同じようにやれ、と書いてある。

それで僕がしたのは、まず

> pear -c ~/.pearrc channel-update pear.php.net
Retrieving channel.xml from remote server
Registry directory is not writeable by the current user

やっぱりダメらしい。

> wget http://pear.php.net/channel.xml

として、channel.xml をダウンロードして、~/pear/ に置いても無駄。さぁて。こう言うときは英語文献に当たるのがイイかも。というわけですぐ発見。

Installation of a local PEAR copy on a shared host

…要するに、日本語版の翻訳が古くて実情に合ってないわけです。やってみましょう。

> pear config-create /home/user/pear .pearrc
Configuration (channel pear.php.net):
=====================================
Auto-discover new Channels     auto_discover    
Default Channel                default_channel  pear.php.net
HTTP Proxy Server Address      http_proxy       
PEAR server [DEPRECATED]       master_server    
Default Channel Mirror         preferred_mirror 
Remote Configuration File      remote_config    
PEAR executables directory     bin_dir          ~/pear/pear
PEAR documentation directory   doc_dir          ~/pear/pear/docs
PHP extension directory        ext_dir          ~/pear/pear/ext
PEAR directory                 php_dir          ~/pear/pear/php
PEAR Installer cache directory cache_dir        ~/pear/pear/cache
PEAR data directory            data_dir         ~/pear/pear/data
PHP CLI/CGI binary             php_bin          
PEAR test directory            test_dir         ~/pear/pear/tests
Cache TimeToLive               cache_ttl        
Preferred Package State        preferred_state  
Unix file mask                 umask            
Debug Log Level                verbose          
PEAR password (for             password         
maintainers)
Signature Handling Program     sig_bin          
Signature Key Directory        sig_keydir       
Signature Key Id               sig_keyid        
Package Signature Type         sig_type         
PEAR username (for             username         
maintainers)
User Configuration File        Filename         ~/.pearrc
System Configuration File      Filename         #no#system#config#
Successfully created default configuration file "~/.pearrc"

うまく行ったっぽい。日本語版にも、英語版にもマニュアルに書いて無いですが、pear config-create して出るメッセージによると、bin_dir は ~/pear/pear に出来ている様なので .cshrc に以下を書き加えます。(Dreamhost は Linux ですが、tcsh がデフォルトシェルっぽい。もし bash を使ってるなら .bashrc に pear マニュアルに書いてある通りすること)参照: .cshrcのカスタマイズ

set path=($HOME/pear)

そして rehash して、

> mkdir pear
> chmod 766 pear
> pear install -o PEAR

とすると、PEAR, Archive_Tar, Console_Getopt が入ります。せっかくなので、XML_RPC も入れときましょうか。

> pear install XML_RPC

此れ以降、Terminal で pear とすると、このローカルコピーにファイルが追加されます。

あと dreamhost では php.ini を(自前ビルドしない限り)個別に用意するのはできないみたいなんで、以下を各スクリプトに追加?マジですか。。。

$old_ini = ini_get('include_path');
ini_set('include_path', $old_ini.':/PATH/TO/HOME/pear/pear/php');

ふぅむ。

<strike>実験用に別の PEAR ローカルコピーを作る</strike>

Date
2006-03-18 (Sat)
Category
php

例えば、普段運用に使ってる PEAR とは別に変な package を入れたいとか、Stable release と、CVS(の開発)版をわけたいとかそう言う時に、PEAR のローカルコピーを作るコトが出来ます。いつもどうすんだっけ?と思っていたので、とりあえずここにメモしておきます。

というか、全て此処に書いてある。

共有ホストにおける PEAR のローカルコピーのインストール

追記: ある種間違いが含まれていたので、別の記事に書きました。

mb_send_mail と SMTP の基礎知識

Date
2006-03-16 (Thu)
Category
php

最初に、実際の使用感とは異なるかもしれない low level プロトコルとして、SMTP を簡単に解説します。SMTP を用いるのに必要なのは以下の3情報です。

  • mail from:
  • rcpt to:
  • data

mail from とはその名の通り差出人情報で、rcpt to は receipt to の略。つまり受取人情報。(技術書などではこれらの二つをあわせて envelope と呼ぶらしい。)そして data がメールで伝えたい内容。

この2つの envelope (mail from と rcpt to)に入力していいのは、我々がメーラで目にするヘッダ情報(つまり“From: 鈴木 一郎 <ichiro@suzuki.com>”など)ではなく、素のemail アドレスだけ、というのは考えれば当たり前ですが、僕の直感とは少し異なっていました。

では我々がメーラで目にするヘッダ情報はどこにあるのでしょう?これは3つめの data のなかにあります。この data として送られる内容の、始まりから数えて最初の により前が message header と呼ばれる“我々がメーラで目にするヘッダ情報”。それ以降全ては message body となり、普段、メーラで見る内容です。

message header 内で日本語を扱う場合、慣習的にほぼ必ず、ISO-2022-JP で文字構造化(character set)してそれを Base64 で可視符号化(encoding method)します。(RFC による標準定義はもちろんあるが、慣習的にほぼ必ずとしたのは、他のオプションもがあるけれども、あまり使われていないようだから。)

詳しくは以下の RFC を参照のこと
RFC 2076: 一般的に使われる message header について
RFC 2047: message header 内での非ASCII 文字の使用について

(正確には SMTP がプロトコルで中身を規定したのが MIME ですね?此処ではプロトコルエンジニアになるのが目的ではないのでとりあえず割愛します。)

さて漸く本題の php に話を戻します。日本語のメールを送りたい時に一番使われるのが mb_send_mail() でしょう。これは上記の問題の多くを隠蔽してくれます。それゆえ挙動がたまに不可解。調べました。

mb_send_mail() は以下の5つの引数を受け取ります。最初の3つが必須であとの2つは optional。

bool mb_send_mail (
	string $to,
	string $subject,
	string $message [, 
	string $additional_headers [, 
	string $additional_parameter]] 
)

(以下で断り無くエンコードと言った場合は、「文字構造化(character set)してそれを Base64 で可視符号化(encoding method)」することを意味します。)

$to は受取人情報を示します。message header に入るべき内容を受け渡すと、関数側でemail address 文字列を自動的に抜き出して rcpt to として MTA (Mail Transfer Agent、例えば sendmail や postfix) に伝え、渡された内容を直接を message header に挿入します。ただしマニュアルページにあるように、エンコードはしません。ので、日本語を使いたい場合は、mb_encode_mimeheader() すべきです。

$subject は message header の件名(Subject)を示します。マニュアルに書いていませんが自動的にエンコードされます

$message は message body を示します。当然ですがエンコードされません

オプションの $additional_headers は、上述の以外の message header を(\n 区切りで)いくらでも挿入可能。通常メーラは複数のヘッダを見つけた場合、下にあるほうを優先するようなので、実は Subject を挿入し上書きするのも可能です。ただしここで入力した内容はエンコードされません

最後の $additional_parameter は MTA に引き渡す特別な option です。詳しくは terminal で man sendmail してほしいですが、よく使われるのは “-f foo@example.com” でしょうか。僕の例では、FreeBSD上、php を apache 経由で起動し mail の送信をした場合、MTA に伝わる mail from は unix username が引き渡されていました。つまり apache の起動 user ですから www です。それでは error message が存在しない www ユーザに帰って困るので、前述の "-f foo@example.com" を使いました。


本当はちゃんとコードも載せるつもりでしたが、眠いので省略します。リクエストがあれば。PEAR のメールクラスなんかも本当は調べたい。。

Bookmarklet 用 Dynamic Script Loader

Date
2006-03-06 (Mon)
Category
javascript

これの続きと言えば続き。Bookmarklet で、任意のページに script 要素を挿入する時、複数ファイルを挿入するとして、それらのファイル同士に依存関係があった場合、読み込みタイミングのせいで、うまく行かないことがあります。

例えば prototype.js と scriptaculous をある bookmarklet で使いたくて、両方読み込むようにするとしても、普通に var s = document.createElement("script");... というのを3個連続させると、何々が定義されてないとか出るわけです。やってみましょう。

試しに振ってみる

まずは prototype.js を読み込んで、変形版 scriptaculous を読み込み、それでそれら両方を使った javascript を実行させています。おそらく一回目にクリックしたときは、コンソールにエラーが出ます。2回目にクリックすると、エントリ全体が揺れる、はず。

しかしネットワーク状況もあるだろうし、動作は一定ではないみたいですね。でも作る側としてはエラーはイヤじゃないですか。と言うわけで作ったのがこの逐次順列読み込みscript。

DySL.js

この object を使えば、読み込む script の順番を完全に制御できます。使い方はこんな感じ。

var dysl = new DySL();
dysl.load(
	"http://tksh.local/beta/alert2.js", 
	{src:"http://tksh.local/beta/alert3.js", id:"abcdedf"}, 
	"http://tksh.local/beta/alert4.js"
);

load メソッドは、src attribute に当たる文字列か、src というラベルを持つ Object を受け付けます。script が持ちうる attribute なら何でもラベルにくっつけてやれば(language とか charset とか)、そのまま反映されます。

欠点としては、読み込まれる側の script に、必ず手を加えなければいけないことでしょうか。ま、是は bookmarklet での使用があるので、多少の手入れは容認しました。ツールを作ればいいのかな。。

Continue reading

Objection Detection: var is

Date
2006-03-02 (Thu)
Category
Web | javascript

前エントリ中で使ったのですが、browser detection のお話です。正確には Object Detection と呼ばれる技。

event の設定には prototype.js 内の Event.observe(...) などが、うまく抽象化されていて使いやすいんですが、設定する event handler が共通ではないとうまく行きません。今、僕のしたいことは IE vs Modern browsers で共通の event handler を見つけることは出来なさそうだったので、切り分けのコードが必要です。

var is という javascript を最初に見たのはありみかさんのあれこれ popup だったような気がするんですが、現行コードには入って無いみたいですね。というわけで調べてみました。

Quirksmode: Object detection

眠いんで説明しませんが理由付けがしっかりされています。

JavaScript Kit: Determining browser type using object detection

違う browser で使える object の表があります。

僕が今回必要なのは IE か Modern Browser(Firefox / Safari / Opera)かそうでないか、くらいなので、こんな感じでした。

var is = {
ie : document.all && !window.opera,
modern : document.getElementById && !document.all,
opera: window.opera && document.getElementById
}

try: document.all
try: document.getElementById
try: window.opera

getElementById だけだと IE 5 以上は true を返しそうです。Opera には document.all があるっぽいから、別途分けなければイケません。なので使う時には…

if (is.modern || is.opera) {
// do something for modern browsers.
} else if (is.ie) {
// do something for modern browsers.
}

こんな感じでしょうか。

DOMNodeInserted

Date
2006-03-01 (Wed)
Category
Web | javascript

僕のよくある悪い癖なのだが、思い付いたことを実現しようといろいろ調査をしていると、目的を実現できそうな切っ掛けとなる技術を発見する。本当にそれでいけんのかいな、とさらに深い調査を始めると、最初に考えていた目的を忘れて、結局その最初に見つけた技術で出来ることを全て試すことになって、あぁ { 面白かった | つまんなかった }で、何してたんだっけ? みたいなことが多い。最悪なのはその結果を全て忘れて、同じことを繰り返したりすることなんだけど、結構やっちゃうんだよね…

と言うわけで今回もまさにそれ。忘れないように個々にメモします。

最近取り組んでいる bookmarklet を使った project 用に、script tag の読み込み完了をイヴェントハンドラに出来ないかどうか調べていました。以下結果。


script tag に onload を付ける。

ちゃんとした仕様書を見つけられた無かったけれどDOM では onload は限られたエレメントでしか fire しないようです。強いて言えばここ DOM-Level-2-Events にすこし載っています。

firefox
ファイル読み込み終了後 fire する
Opera 8.51
fire しない
Windows IE 6.0
fire しない
Safari 1.3.2
fire しない

と、見事に firefox 以外は fire しません。当たり前ですね。余談ですが、Firefox では img タグでも onload が fire します。となると、src attribute がつくタグは全て onload が fire するんじゃないかと期待できそうですが、それはそれで意味が通じます。特に“読み込み終了後 fire” というのは非常に通好みと言うか。以下、実験に使ったコード抜粋です。

<script type="text/javascript" onload="javascript:void(alert('onload'));" src="alert.js"></script>

alert.js には

alert("in script");

とだけあります。

onload sample

body に Listner Object的なものを付けてscript タグの挿入を監視

上でも黙って Quirksmode にリンクしましたけれども、javascript で event 周りをやろうと思ったら Quirksmode は素晴らしい文章の宝庫です。で、ずばり The events というページはすこからさき全ての文章への portal になっている、と言うか。以下のページ群は見ているだけでも楽しい様な browser で使用できる event ハンドラが列挙されています。(Opera 向けのページは何処にあるのだろう?)

Quirksmode の記述とやや異なりますが、Safari は DOM Level 2 Events を全て実装しているとあります。Web Specifications Supported in Opera 8 によれば Opera 8 も同様のようです。Free になったのは此のバージョンですから、まぁこれが主流になると考えて差し支えないでしょう。

と言うわけで、本題の DOMNodeInserted です。仕様書より引用すると、

Fired when a node has been added as a child of another node. This event is dispatched after the insertion has taken place. The target of this event is the node being inserted.

ですから、DOM Node を何処か別の DOM Node に挿入が完了した時に fire されるようですね。試してみましょう。以下のページにて。


DOM Node Inserted Sample

タイミングを計るのは難しいですが、上記 sample ページで読み込んでいるコードはしていることは同じですが、コメントを使ってファイルサイズを稼いでいます。やってもらえばわかりますが、DOMNodeInserted で fire される alert(MutationEvent と表示される)が出てから、alert2.js の alert (in script と表示される)が呼ばれます。(分かりにくい)

あとキモはこのコードでしょうか。

document.body.addEventListener('DOMNodeInserted', function(e){
alert(e);
}, false);

DOMNodeInserted で fire される function には デフォルトで MutationEvent という object が渡されます。その property を見れば、どんな DOM Node が挿入されたかわかる、という仕組みです。


が、Windows IE でこれを実現できる event handler を見つけられていないので…結局意味ないじゃん!みたいな。ただ listener object というアイデア自体はいけそうですね。

Return to Page Top