mod_rewrite でURLを書き換える場合の PHP_SELF の値は、RewriteRule を .htaccess に書くか httpd.conf に書くかによって違ってくる。http://example.com/foo/bar を http://example.com/index.php に書き換える場合について例示すると以下のようになる。
.htaccessに書く場合
RewriteRule ^foo/bar$ index.php
index.php でアクセスできるPHP_SELFの値は /index.php になる。
httpd.confに書く場合
RewriteRule ^/foo/bar$ /index.php
index.php でアクセスできるPHP_SELFの値は /foo/bar になる。
フレームワークの中には .htaccess で書き換えることを前提としてパス処理を行っているものがあり(CakePHP 1.2など)、httpd.confで書き換えをする場合には何らかの回避策をとる必要がある。
(1) PTオプションを使用する
RewriteRule に passthrough|PT オプションを指定する。
RewriteRule ^/foo/bar$ /index.php [PT]
このオプションを指定した場合、書き換え後のURLに対してAliasやRedirectの適用が行われるようになることに注意(元々そういった用途に使うためのオプション)。
(2) フレームワークレベルで設定する
CakePHP 1.2の場合はindex.php内Dispacherクラスのコンストラクタ第2引数で、PHP_SELFに替わる基準パスを指定できる。
$Dispatcher = new Dispatcher(null, ''); //空文字列でルートを意味する
……
技術的に言うとこれはURL書き換え時に request_rec 構造体の uri メンバを書き換えるか否かの違い。.htaccess でURLを書き換えた場合は書き換え後のURLに対して internal-redirect が発生するらしく、結果として handler の中から書き換え後の uri が見えるようだ(RewriteLogから推測)。
http://twitter.com/serpere
「フォローしないと面白くない」とは聞いていたので、とりあえず登録時におすすめされた有名人アカウントを半分くらい、それから購読しているブログの中でアカウントがすぐ判明した何人かをフォローして開始。
当たり前だが、まださっぱり面白さが分からない。混雑したファミレスの中で、他テーブルの雑談を聞くともなしに聞きながら独り言をつぶやいているような、ものすごい違和感。でもそういう雑談に思わず心の中で突っ込みを入れてしまうことがあるように、@xxx で突っ込みを入れていけば面白くなってくる…のだろうか?
会話のための会話を楽しめる人向けというか、ある意味では最も純粋なコミュニケーション・ツールという気もする。当面はひたすらフォローする人を増やしながら様子を見ていこう。
SBCLで使用可能なexternal-formatの話の続き。
結局 SB-IMPL::*external-formats* を見ればわかるということで解決はしたのだが、SBCLはそれ自体がLispで書かれているので、関数readを使ってソースファイルからLispフォームを読み出し、内容を解析することでexternal-formatの定義を抽出することができるのではないか、と思いついた。
結論から言うと、一応は可能だった。しかし想像していたよりもはるかに面倒くさかった。以下はその苦労の記録である(完全なコードは最後に載せてある)。
基本的な戦略
まずfindとgrepによる下調べで次のようなことが判明した。
- external-formatは3種類のマクロで定義されている
- define-external-format
- define-external-format/variable-width
- define-multibyte-encoding
- その定義が含まれているのは以下のファイル群である
- src/code/fd-stream.lisp
- src/code/external-formats/*.lisp
よってこれらのファイルを read で読んで、該当するマクロフォームからexternal-formatの名前部分を取り出していけば良いはずである。
(defun external-format-definition-p (form)
(when (listp form)
(case (first form)
((define-external-format define-external-format/variable-width) (second form))
(define-multibyte-encoding (third form))
(otherwise (apply #'append (mapcar #'external-format-definition-p form))))))
障害1.リーダーマクロ
対象となるソースファイルの中には #! で始まる独自のリーダーマクロを使ったコードが含まれており、そのままではreadで読み込めなかった。このマクロの正体が分からず随分苦労したのだが、どうやら既存の処理系でSBCL自体をコンパイルするときに、#!+ および #!- という形式で、それぞれ #+ と #- に類似する機能を提供するためのものらしい(参考)。そういう特殊な役割を持ったマクロであるために、実行時に使うことはできないようだ(実装は src/cold/shebang.lisp の中にある sb-cold::shebang-reader だが、実行時には sb-cold パッケージは存在しない)。
単純に #! を無視するだけのリーダーマクロでは現在の環境で動かないコードまで読まれてエラーになったので、#+ および #- の実装に処理を転送することにして、どうにか動くようにした。
(defun shebang-reader (stream sub-character infix-parameter)
(let ((next-char (read-char stream)))
(funcall (if (char= next-char #\+) #'sb-impl::sharp-plus #'sb-impl::sharp-minus)
stream sub-character infix-parameter))
(values))
障害2.パッケージ参照
read は、読み出したLispフォームに存在しないパッケージへの参照が含まれているとエラーを起こす。
ところがSBCLのソース中には、ソース中の表記(SBCLのコンパイル中に使われる名前?)と実行時の名前が異なるというパッケージが存在することが分かった。例えばSB!IMPL(動作中はSB-IMPL)、SB!THREAD(動作中はSB-THREAD)などである。
ソースを注意深く読み、試行錯誤を繰り返した結果、sb-impl::bootstrap-package-not-found エラーに対し sb-impl::debootstrap-package 再起動を行ってやれば、これらのパッケージをソース中に表記された名前で参照できるということが分かった。
(defmacro with-debootstrap-package (&body body)
`(handler-bind ((sb-impl::bootstrap-package-not-found
#'sb-impl::debootstrap-package))
,@body))
例:
(with-debootstrap-package (find-package "SB!IMPL"))
; => #<package "SB-IMPL">
</package>
……
以上の障害(本当はもっといろいろあるが)を乗り越え、ようやく意図通りの動作をするようになった。以下に全コードを載せておく。しかしexportされていないシンボルを使いまくっているので、バージョンが違うと動かない可能性がある(sbcl-1.0.23-x86-darwin で動作確認)。もちろん、SBCLでしか動かない。
(続きを読む…)
mod_dosdetectorの改造版、mod_dosdetector-forkのバージョン1.0.0を公開します。
mod_dosdetector-fork-1.0.0.tar.gz
(GitHubプロジェクトページ)
プログラム本体は3ヶ月前とほぼ全く同じ状態ですが、より使いやすくするために以下のような追加・修正を行っています。
- 詳細な説明を含むREADMEを追加
- サンプル設定ファイル(dosdetector-sample.conf)を追加
- Makefileを修正(installターゲットでビルドオプションを指定できるようになった)
READMEはとりあえず日本語で書いてみましたが、いずれ英訳するつもりです。またバージョンが1.0.0という切りの良い数字になっているのは、オリジナル(最新版0.2)との混乱を避けるためであって、特に深い意味はありません。
READMEにも含まれていますが、オリジナルと大きく違うのは以下の3点です。
- DoSチェックの対象としないアクセスを環境変数で指定できる
- 不要なサブリクエストの生成処理を取り除くことでパフォーマンスが改善されている
- 共有メモリ処理が改善されている
それぞれが技術的に何を意味するのかはこのブログのmod_dosdetectorタグを参照してください。
またせっかくなのでオリジナルの配布物に含まれていたspecファイルも全面的に修正しておきました。RPMパッケージを作るにはspecファイルとtarballを適切な場所に配置して
rpmbuild -bb mod_dosdetector-fork.spec
を実行してください。以下のファイルを含むRPMパッケージが出来上がります。
/etc/httpd/conf.d/dosdetector.conf
/usr/lib/httpd/modules/mod_dosdetector.so
CentOS 5上でしかテストしていませんが、Apache 2.2が入っているFedora等ならばうまくビルドできるのではないかと思います。
マニュアルに載ってなくて悩んでいたが、ソースを読めば良いだけだと気が付いた。external-format 関連のコードは src/code/fd-stream.lisp にあり、*external-formats* 変数に必要なデータが収められている。sbcl-1.0.30で全ての名前を表示すると次のようになる。
(mapcar #'caar SB-IMPL::*external-formats*)
;; =>
(:UCS-2BE :UCS-2LE :SHIFT_JIS :EUC-JP :GBK :CP1258 :CP1257 :CP1256 :CP1255
:CP1254 :CP1253 :CP1252 :CP1251 :CP1250 :ISO-8859-14 :ISO-8859-13 :ISO-8859-11
:ISO-8859-10 :ISO-8859-9 :ISO-8859-8 :ISO-8859-7 :ISO-8859-6 :ISO-8859-5
:ISO-8859-4 :ISO-8859-3 :ISO-8859-2 :CP874 :CP869 :CP866 :CP865 :CP864 :CP863
:CP862 :CP861 :CP860 :CP857 :CP855 :CP852 :CP850 :CP437 :X-MAC-CYRILLIC
:KOI8-U :KOI8-R :UTF-8 :LATIN-9 :EBCDIC-US :ASCII :LATIN-1)
別名も含め一覧表示する場合は
(mapcar #'first SB-IMPL::*external-formats*)
;; =>
((:UCS-2BE :UCS2BE) (:UCS-2LE :UCS2LE) (:SHIFT_JIS :SJIS :|Shift_JIS| :CP932)
(:EUC-JP :EUCJP :|eucJP|) (:GBK :CP936)
(:CP1258 :|cp1258| :WINDOWS-1258 :|windows-1258|)
(:CP1257 :|cp1257| :WINDOWS-1257 :|windows-1257|) (:CP1256 :|cp1256|)
(:CP1255 :|cp1255| :WINDOWS-1255 :|windows-1255|) (:CP1254 :|cp1254|)
;... 長くなるので省略 ...
293ページ脚注に載っているURLはリンク切れになっている。SpamAssassinが提供するSPAMとHAMのコーパスはここ。
ただし本に載っている通りのコードでは start-of-file でエラーが出た。環境はSBCL@MacOS X。コーパスの中にiso-8859-1でエンコードされたファイルが混じっているのが原因らしい。with-open-file に :external-format を指定したら動作した。
(defun start-of-file (file max-chars)
(with-open-file (in file :external-format :latin1)
(let* ((length (min (file-length in) max-chars))
(text (make-string length))
(read (read-sequence text in)))
(if (< read length)
(subseq text 0 read)
text))))
SBCLで使用可能な :exteral-format の一覧を探しているのだが、マニュアルのどこに書いてあるのか分からない…。

もんじゅMCスクエア
久しぶりに良く晴れた夏の休日、敦賀半島の突端にある高速増殖炉「もんじゅ」に行ってきた。とはいえ一般人はもんじゅそのものを見ることはできないので、その手前の「MCスクエア」という建物で展示物の見学&お勉強。人がほとんどいなかったせいもあって、急ぎ足ながら職員(研究員?)の方から直接説明を受けることができた。
それまで「高速増殖炉」という名称や「消費した以上の燃料を製造」とかいう謳い文句から、何となくアヤシいものを想像してしまっていたのだが、コンセプトとしては非常に明快なものだということが分かった。私が理解したところによればこんな感じだ:
そのまま燃やせる乾いた薪と、そのままでは燃やせない湿気った薪がある。
数は湿気った薪の方が圧倒的に多いので、捨ててしまうのはもったいない。
そこで乾いた薪を燃やして水を沸かすときに、周りに湿気った薪を並べておいて、
ついでに乾かすことにしよう。
例えは私が考えたものだが、そこまで外してはいないと思う。つまり乾いた薪=U235,Pu、湿気った薪=U238、乾いた薪を燃やしながら湿気った薪を乾かす=U235やPuで発電しながら、発生する中性子でU238をPuに変換する。消費した以上の燃料を生み出すというのは、10本燃やす間に11〜12本くらい乾かすことができる、という程度の意味。摩訶不思議なプロセスで燃料が”増殖”するわけではない。
あと熱の運搬に「液体ナトリウム」という、日常的感覚からはかけ離れつつも基礎的な化学知識で危険性が理解できる代物を使わなければいけない、という点がすごく不安だったのだが、実は運用上優位な点もいろいろとあるらしい。沸点が高いので常圧のまま運用できるとか、熱伝導率が高いので発電効率も高いとか、金属との相性が良いので配管の腐食が起こりにくいとか……。しかしそれでも事故が起こったのは事実なわけで、やはりナトリウムの扱いが一番難しいところなのでしょうか?と尋ねたところ、「様々な困難を克服して今がある」というような回答が返ってきた。また「ナトリウム漏れは、技術屋的には『ああ漏れたか』という程度の話だ」とも。……ここからは完全に私の想像なのだが、おそらく現場の研究員としてはナトリウム漏れ事故も「ナトリウムが漏れた、ではどうしよう、温度計が原因だから温度計を改良しよう」とかいう通常の技術的課題という認識でしかなく、「ナトリウムが漏れた、ではもう駄目だ失敗だ」的な世間の反応がもどかしいのではないだろうか。
もちろん技術的に可能だからといって、無限に税金を投入し続けて良いという話にはならない。本当に割に合うのかという議論は必要だ。また周囲の住民からすれば、何をどう説明されたところでそう簡単に割り切れるものではないだろう。しかしともすれば得体の知れない巨大事業と見られがちな高速増殖炉事業も、その裏側には確実に人間の営みが存在する。それをはっきりと感じ取ることができたのが収穫だった。
……
敦賀半島には海水浴場がたくさんあり、もんじゅへ向かう途中の道のりでも浜辺を埋め尽くす大勢の海水浴客を見ることができた。しかし半島の先端にあるもんじゅに近付くにつれて人も車も少なくなり、MCスクエアの駐車場は閑散としていた。皆もっともんじゅについて知るべき!と思った。
『実践Common Lisp』286ページの脚注8、リスト指示子についての説明(翻訳)が完全に混乱していて、全く理解できない。
HyperSpecを参照しながら、自分なりに読み解いてみた。
1.4.1.5 Designators
本書で「指示子」と訳されている designator とは、別のオブジェクトを意味する/指し示すオブジェクトである。例えば format 関数の最初のパラメータに t を与えると *terminal-io* を与えたのと同じことになるが、これは t というシンボル・オブジェクトが *terminal-io* に保持されるストリーム・オブジェクトを意味する/指し示すからだ、と言うことができる。
あるオブジェクトがどのオブジェクトを指し示すかというルールは、指示子の型によって決められている。だから指示子は普通、型名を伴って
- <<type>> designator : 〜型の指示子
- designator for a <<type>> : 〜型に対する指示子
とかいう呼び方をする(訳語は私による)。例えばシンボル t が *terminal-io* を指し示すというルールは stream desinator によって決められている。
……
『実践Common Lisp』286ページ脚注に戻ると、ecase のキーは “designator for a list of objects” と定義されている。そこでHyperSpecの用語集で list designator のところを読むと、次のようなルールが書いてある。
- nilではないアトム -> そのアトムを唯一の要素として持つリストを指し示す
- 普通のリスト -> そのリスト自身を指し示す
つまり指定できるのは「nilではないアトム」か「リスト」のどちらかで、どちらを指定したとしてもリストと見なされる。
よって ecase の動作もキーがリストであることを前提として説明される。
If the test-key is the same as any key for that clause, the forms in that clause are evaluated as an implicit progn, and the values it returns are returned as the value of the case, ccase, or ecase form.
(そもそもこの短い脚注で指定子の概念にまで言及したせいで、翻訳も混乱してしまったのではないかと思う。『ecaseのキーにはリストも指定できる。リストを指定した場合はいずれかの要素が一致する場合にマッチしたと見なされる』くらいの言い方で良かったのではなかろうか…)
インストールまで。標準の設定では sshd と ftpd しか有効にならない。
古い Qpopper が動いているサーバでPOP3サービスに対する攻撃を防御する必要が生じたので、POP3用の設定を追加した。
blockhosts.cfgの設定
LOGFILES に maillog のパスを追加。
LOGFILES = [ "/var/log/secure","/var/log/maillog", ]
ALL_REGEXS にログパターンを追加。qpopper用のパターンは標準で含まれてはいるが、実行ファイルの名称(=ログに記録されるプログラム名)が異なっていたのと、不正パスワード以外の失敗パターンも捕捉したかったので、下記のように追加した。
# "qpopper-Fail":
# r'{LOG_PREFIX{qpopper}} .* \({HOST_IP}\): -ERR \[AUTH] Password supplied ',
"qpopper-Fail-Password":
r'{LOG_PREFIX{in.qpopper}} .* \({HOST_IP}\): -ERR \[AUTH] Password supplied ',
"qpopper-Fail-Access":
r'{LOG_PREFIX{in.qpopper}} .* \({HOST_IP}\): -ERR \[AUTH] Access is blocked ',
"qpopper-Fail-PAM":
r'{LOG_PREFIX{in.qpopper}} .* \({HOST_IP}\): -ERR \[AUTH] PAM authentication failed ',
ENABLE_RULES の正規表現を修正して、先ほど追加した qpopper 用ルールを有効にしておく。この設定を明示的に行わないと sshd と ftpd しか有効にならないので注意が必要。
ENABLE_RULES = r'(?i)(sshd|.*ftpd|qpopper).*'
テスト
dry-run オプションを付けて実行。
sudo blockhosts.py --verbose --dry-run
hosts.allowの修正
blockhosts.py の行にqpopperを追加する。
in.qpopper, in.proftpd: ALL: spawn /usr/bin/blockhosts.py --verbose --echo "%c-%s" >> /var/log/blockhosts.log 2>&1 : allow
designMode/contentEditable を使用したWYSIWYGエディタが、IEのバージョンを8に上げたら正常に動かなくなった、という相談を受けた。ほとんどの機能は正常なのだが、画像の挿入だけがうまくいかないという。
いろいろ調べた結果、execCommand メソッドで InsertImage を実行する前に、対象となる window の focus メソッドを呼び出せば正常に動作することが分かった。
var iframe = document.getElementById('editor');
iframe.contentWindow.document.designMode = 'on';
function insertImage(path) {
iframe.contentWindow.focus(); //ココ
iframe.contentWindow.document.execCommand('insertimage', false, path);
}
問題の解決にあたっては、下記のフォーラムなどで「テキスト選択中なら正常に動く」という証言があったことがヒントになった。
execCommand – specifically InsertImage stops working with IE8 upgrade