すっかり放置しすぎてアレですね。今は OpenPNE とか会社とかのブログばっかり書いてる状況ですね。

なんで戻ってきたかっていうと気軽に表が書きたいなと思ったからですね。

個人的なメモなので通り過ぎるといいと思います。そのうちどこか普通の場所でお披露目します。

説明 LDAP OpenID SREG OpenID AX OpenSocial
識別名 ×
氏名 × ×
× ×
× × ×
ミドルネーム × × ×
部署名 × × ×
ファックス ? × × ×
メインの電話番号 × × ×
自宅電話番号 ? × ×
勤務先電話番号 ? × ×
自宅の番地 ? × ×
自宅の番地2 ? × ×
勤務先の番地 ? × ×
勤務先の番地2 ? × ×
勤務先の市区町村 ? × ×
メモ × × ×
自宅の市区町村 ? × ×
自宅のメールアドレス ?
携帯電話 ? × ×
ファックス ? × ×
ポケットベル ? × × ×
オフィス × ×
自宅の都道府県 ? × ×
勤務先の都道府県 ? × ×
役職 × ×
Webページ × ×
ニックネーム(表示名)
性別 ×
生年月日 × ×
自宅の郵便番号 ?
勤務先の郵便番号 ? × ×
自宅の国 ? ×
勤務先の国 ? × ×
言語 ×
タイムゾーン ×
敬称 × × ×
名前のサフィックス × × ×
誕生年 × × ×
誕生月 × × ×
誕生日 × × ×
好きなIM × × ×
AOLのIMアカウント × × ×
ICQのIMアカウント × × ×
MSNのIMアカウント × × ×
Yahoo! のIMアカウント × × ×
Jabber のIMアカウント × × ×
Skype のIMアカウント × × ×
ブログのURL × × ×
LinkedIn の URL × × ×
Amazon の URL × × ×
Flickr の URL × × ×
del.icio.us の URL × × ×
spokenname × × ×
オーディオでの挨拶URL × × ×
ビデオでの挨拶URL × ×
伝記 × × ×
画像 × ×
画像(16x16) × × ×
画像(32x32) × × ×
画像(48x48) × × ×
画像(64x64) × × ×
画像(80x80) × × ×
画像(128x128) × × ×
画像(160x120) × × ×
画像(320x240) × × ×
画像(640x480) × × ×
画像(120x160) × × ×
画像(240x320) × × ×
画像(480x640) × × ×
favion × × ×
自己紹介 × × ×
活動 × × ×
住所 × × ×
× × ×
身体的特徴 × × ×
好きな本 × × ×
好きな車 × × ×
子供について × × ×
現在地 × × ×
酒を飲むか × × ×
民族 × × ×
ファッションについての考え × × ×
好きな食べ物 × × ×
幸せなときはいつか × × ×
好きなヒーロー × × ×
ユーモアについての姿勢 × × ×
興味のあること × × ×
好きな仕事 × × ×
職業 × × ×
生活環境 × × ×
目的 × × ×
好きな映画 × × ×
好きな音楽 × × ×
NETWORK_PRESENCE × × ×
ペットについて × × ×
政治的見解 × × ×
テーマソング × × ×
好きな格言 × × ×
宗教的見解 × × ×
恋愛観 × × ×
怖いこと × × ×
出身校 × × ×
性的嗜好 × × ×
喫煙状況 × × ×
好きなスポーツ × × ×
現状のステータス × × ×
タグ × × ×
嫌いなこと × × ×
好きなこと × × ×
好きなテレビ × × ×

かなり適当だけどまあ。途中で飽きたし。

年が5桁の DateTime::format() の第一引数に 'Y' を指定すると、年が4桁に丸められて返ってくる

理由と回避策はこれから調べる。何のための DateTime オブジェクトなんだ……

    • -

追記

PHP のコード追いました。 DateTime::format() と date() は両方とも (PHP 関数ではない方の) date_format() という関数を呼んでる>< すごくいやな予感><

    • -

追記2

case 'Y': length = slprintf(buffer, 32, "%s%04d", t->y < 0 ? "-" : "", abs((int) t->y)); break;

お勤めご苦労様です!

mod_rewrite + Suhosin Extension (PHP) の組み合わせで構築されたサイトを Sleipnir でブラウズするとログイン状態が継続できない場合がある

mod_rewrite + Suhosin Extension (PHP) の組み合わせで構築されたサイトを Sleipnir でブラウズするとログイン状態が継続できない場合がある」

なにを言っているのか(ry

まあマジ話ですよ。アプリにとんでもない欠陥があるんじゃないかと本気で焦っちまったぜ。

現象は以下のような環境で発生します。

  • suhosin 拡張が有効になった PHP を使用している
  • suhosin.session.cryptua が on (デフォルト)
  • /favicon.ico でアクセスできるリソースが存在しない
  • mod_rewrite の設定で、存在しないファイルへのアクセスは PHP スクリプトに内部リダイレクトされる

というか有り体に言えば、suhosin 拡張を有効にして認証有りの symfony アプリを設置して favicon.ico を置かない状態にした上で Sleipnir でブラウズすれば発生すると思います。

なんでこんなことが?

OpenPNE 開発談義というスカイプチャットルームの俺の発言をそのまま引用します。

[09/02/20 19:47:34] 海老原昂輔 (Kousuke Ebihara): 簡単に言うと、
1. suhosin 拡張によってセッションがUAの値に基づいて作られる
2. Sleipnir でログインとかページ遷移とかする
3. Sleipnir が通常とは異なるUAで /favicon.ico に GET しようとする
4. だが /favicon.ico はない
5. mod_rewrite により、 /favicon.ico への GET が OpenPNE3 の PHP スクリプトに行く
6. セッション生成時のUA と /favicon.ico へのアクセス時の UA が違うため、 suhosin がセッションを無効化する
7. ログアウト

原因発覚にいたる経緯と解説

原因がまったく検討つかなかったんですが、限定環境でしか発生しないことから、なんとなく「Sleipnir のリクエストヘッダがおかしいんじゃ?」「Suhosin がなにかやらかしているんじゃ?」という予感はしていました。ということで開発環境の Suhosin を無効にしてみたら正常な挙動になった! やっぱり!

ということで設定項目をひとつひとつ無効にしてみたら suhosin.session.cryptua が on のときに現象が発生することが判明! ここまできたらもうこっちのものだ!

suhosin.session.cryptua が on だとどうなる?

そもそも suhosin ってなんだよって人は http://www.hardened-php.net/ 行ってください。

で、 suhosin.session.cryptua が何者かについては、(字面から想像つきますが)、 http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.cryptua にて以下のように説明されています。

suhosin.session.cryptua
    * Type: Boolean
    * Default: On
Flag that decides if the transparent session encryption key depends on the User-Agent field. (When activated this feature transparently adds a little bit protection against session fixation/hijacking attacks)

ですよねー。

でもじゃあなんでこれが Off になってると正しく動くのさ? なんか変なことやってんじゃないの? ということでソースコードを追ってみました。(http://download.suhosin.org/suhosin-0.9.27.tgz から入手可能)

この設定が実質的に影響するのは session.c の以下の部分のみ。

397 char *suhosin_generate_key(char *key, zend_bool ua, zend_bool dr, long raddr, char *cryptkey TSRMLS_DC)
398 {
399     char *_ua = NULL;
400     char *_dr = NULL;
401     char *_ra = NULL;
402     suhosin_SHA256_CTX ctx;
403 
404     if (ua) {
405         _ua = sapi_getenv("HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")-1 TSRMLS_CC);
406     }

:

424     if (_ua) {
425         suhosin_SHA256Update(&ctx, (unsigned char*)_ua, strlen(_ua));
426     }

まあ特におかしなことをやっている様子はないと。じゃあやっぱりおかしいのは Sleipnir ではということに。

SleipnirUA 変わってるんじゃ……?

まあとにもかくにもリクエストヘッダを見てみようかと Sleipnir 界隈を漁ったんですが、 Firefox でいう LiveHttpHeader みたいなプラグインはないんですね。あれすごい便利なのに。

ということでパケットキャプチャソフト(Wireshark ってやつ)を落としてきて、そいつで解析しました。

リクエスト1

POST /member/login/authMode/MailAddress HTTP/1.1\r\n
:
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727) Sleipnir/2.8.2\r\n

リクエスト2

GET /favicon.ico HTTP/1.1\r\n
:
User-Agent: Sleipnir/2.8.2\r\n

おかーさーん! この子 UA 勝手に切り替えちゃってるよー!

なんでこんなことに……と泣きそうになりながらヘッダを洗っていくと、 UA が 「Sleipnir/2.8.2」 となるのは favicon.ico に対してのみ、ということに気づきました。いやしかしそれなら PHP スクリプトにはなんの関係もなかろう、なぜ suhosin の設定変えれば動くんだよ、とツッコミを入れながらレスポンスヘッダをよく見てみると、

HTTP/1.1 404 Not Found\r\n

アーッ!!! mod_rewrite

mod_rewrite を見てみる

見てみる。といっても symfony デフォルトのままだけどね。

<IfModule mod_rewrite.c>
  RewriteEngine On

  # uncomment the following line, if you are having trouble
  # getting no_script_name to work
  #RewriteBase /

  # we skip all files with .something
  #RewriteCond %{REQUEST_URI} \..+$
  #RewriteCond %{REQUEST_URI} !\.html$
  #RewriteRule .* - [L]

  # we check if the .html version is here (caching)
  RewriteRule ^$ index.html [QSA]
  RewriteRule ^([^.]+)$ $1.html [QSA]
  RewriteCond %{REQUEST_FILENAME} !-f

  # no, so we redirect to our front web controller
  RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

どう見ても index.php 叩きに行きます、本当にありがとうございました。

解決策

これもチャットのコピペですが、以下の解決策がありそう。

[09/02/20 19:49:10] 海老原昂輔 (Kousuke Ebihara): まあ対処方法としては、
[09/02/20 19:52:30] 海老原昂輔 (Kousuke Ebihara): A. セッション生成時に UA を使わないようにする
 a. suhosin 拡張自体を無効化
 b. suhosin.session.cryptua を off
B. /favicon.ico へのリクエストで PHP を叩かせないようにする
 a. favicon.ico を置く
 b. mod_rewrite などの設定を変更し favicon.ico へのリクエストが来ても PHP スクリプトに内部リダイレクトさせない
[09/02/20 19:53:14] 海老原昂輔 (Kousuke Ebihara): 4つのうちのどれかを選ぶ感じかなと

他にも以下が思いついた。

なんか functional test が別のアプリケーションの myUser を読みにいってた

なんか functional test が別のアプリケーションの myUser を読みにいってて、今まで書いてたテストがことごとく落ちるようになってた。

さんざん悩んだ(1.5hくらい)挙げ句、 symfony cc したら解決した。 bootstrap 内でキャッシュクリアしているもんだと思って完全に油断してた。

というかなんだったんだこれは。。。落ち着いたら調べてみるけど><

sfBrowserBase::doClick() によるファイルアップロード時に MIME-type を指定できるようにするパッチを送った

sfBrowserBase::doClick() によるファイルアップロード時に MIME-type を指定できるようにするパッチを symfony に送った。いやまあ MIME-type 使うとかないわーって話かもしれないけど、空文字列でハードコーディングして POST するほうがもっとないわーって思ったので、かっとなって作った。

http://trac.symfony-project.org/ticket/5748

Index: lib/util/sfBrowserBase.class.php
===================================================================
--- lib/util/sfBrowserBase.class.php	(リビジョン 14901)
+++ lib/util/sfBrowserBase.class.php	(作業コピー)
@@ -746,7 +746,17 @@
       }
       else if ($nodeName == 'input' && $element->getAttribute('type') == 'file')
       {
-        $filename = array_key_exists($elementName, $arguments) ? $arguments[$elementName] : sfToolkit::getArrayValueForPath($arguments, $elementName, '');
+        $file = array_key_exists($elementName, $arguments) ? $arguments[$elementName] : sfToolkit::getArrayValueForPath($arguments, $elementName, '');
+        if (is_array($file))
+        {
+          $filename = isset($file['name']) ? $file['name'] : '';
+          $filetype = isset($file['type']) ? $file['type'] : '';
+        }
+        else
+        {
+          $filename = $file;
+          $filetype = '';
+        }
 
         if (is_readable($filename))
         {
@@ -761,7 +771,7 @@
 
         unset($arguments[$elementName]);
 
-        $this->parseArgumentAsArray($elementName, array('name' => basename($filename), 'type' => '', 'tmp_name' => $filename, 'error' => $fileError, 'size' => $fileSize), $this->files);
+        $this->parseArgumentAsArray($elementName, array('name' => basename($filename), 'type' => $filetype, 'tmp_name' => $filename, 'error' => $fileError, 'size' => $fileSize), $this->files);
       }
       else if (
         $nodeName == 'input'


さすがにチケット作るの 4 回目、パッチ作るの 3 回目ともなるとお手の物ですねもう。英語力は相変わらずだけど!(てか英語間違ってるの気づいて修正したいけど Description 変更権限与えられていないのね><)