セッションIDの構成文字

PHPがデフォルトで生成するセッションIDの構成文字は何だろう。
マニュアルにはsession_id関数で指定できるセッションIDに制限があることは記述されています。

セッションハンドラによっては、セッション ID として使用できる文字に 制限がある場合があります。例えば、ファイルによるセッションハンドラは セッション ID として使える文字は a-z A-Z 0-9 , (カンマ) そして - (マイナス) に限られます!

PHP: session_id - Manual

では、実際に生成される文字列はどうなのかわかりません。分からないなら調べます。

<?php
session_start();
$ids = array();$chars = array();for($i = 0; $i < 10000; $i++) {
$id = session_id();
foreach(str_split($id, 1) AS $char) {
$chars[$char] = isset($chars[$char])? $chars[$char]+1: 1;
}$ids[] = $id;session_regenerate_id();
}
ksort($chars);
var_export($chars);

結果は

array ( 0 => 9157, 1 => 8933, 2 => 9067, 3 => 8915, 4 => 9036, 5 => 9130, 6 => 9105, 7 => 8984, 8 => 7743, 9 => 7803, 'a' => 7886, 'b' => 7938, 'c' => 7704, 'd' => 7896, 'e' => 7814, 'f' => 7882, 'g' => 8051, 'h' => 7687, 'i' => 7775, 'j' => 7891, 'k' => 7708, 'l' => 7761, 'm' => 7896, 'n' => 7767, 'o' => 7846, 'p' => 7875, 'q' => 7753, 'r' => 7938, 's' => 7689, 't' => 7833, 'u' => 7676, 'v' => 7861, )

0-9a-vらしいです。記号どころかwxyzすら出てきません。32進表示表示らしいです。

一応、ソースも見てみます

// ext/session/session.c line.343
PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */
// 省略
if (PS(hash_bits_per_character) < 4
                        || PS(hash_bits_per_character) > 6) {
                PS(hash_bits_per_character) = 4;

                php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ini setting hash_bits_per_character is out of range (should be 4, 5, or
 6) - using 4 for now");
        }
        j = (int) (bin_to_readable((char *)digest, digest_len, buf, PS(hash_bits_per_character)) - buf);

あれ?bin_to_readableがバイト列を文字列に変換してるらしいですけど、その前にhash_bits_per_characterとか言う設定値がどうのとういう警告投げる個所が……

session.hash_bits_per_character により バイナリのハッシュデータを何らかの可読なデータに変換する際、 それぞれの文字に何ビットストアさせるかを定義することが可能です。 指定可能な値は、'4' (0-9, a-f)、'5' (0-9, a-v) そして '6' (0-9, a-z, A-Z, "-", ",") です。

PHP: 実行時設定 - Manual

遠回りをしてしまいましたがデフォルトのセッション生成を使う場合session.hash_bits_per_characterによって1文字あたりの情報量、翻って構成文字が設定できるということでした。

Doctrineのモデルクラス接頭辞に"_"を入れると面倒

Doctrineでは、managerやconnectionの属性としてDoctrine_Core::ATTR_MODEL_CLASS_PREFIXに接頭辞を設定することができます。
また、Doctrine_CLIyamlからモデルクラスを生成する場合は$config['generate_models_options']['classPrefix']を設定することで接頭辞を持ったモデルクラスを生成します。
で、この接頭辞に"_"(アンダーバー)を含めてしまうとクラスのロードに失敗するという現象に遭遇しました。
早速Doctrine_Core::modelsAutoloadを覗いてみると

<?php
// line.1158
            $class = self::$_modelsDirectory . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

というように、問答無用でクラス名の_をディレクトリセパレータに置換してファイルパスに使っています。
Doctrine_CLIでモデルクラスを生成する場合にはデフォルトではこのような生成はされません。このような生成がされるのは$config['generate_models_options']['pearStyle']=trueとした時のみです。
ということで$config['generate_models_options']['pearStyle']=trueにして生成すると余計なディレクトリわけが出てきてしまいますが、問題なくロードされるようになりました。

お名前.com 共用サーバSDでSPFレコードを追加してみた。

5月に一人暮らしははじめようとしているんですが、この機会に今まで自宅サーバにあったメールサーバを以前から放置していたお名前.comの共用サーバに移すことにしました。せっかくなのでSPFレコードを設定することにしました。

実際にこの共用サーバのsmtpを使ってメールを送信してみたところ下記のような転送が行われていました。

Received: from smtp.zero.jp (smtp06.zero.jp [210.157.5.236])
	by mail.example.com (Postfix) with ESMTP id 833D2288324
	for <master@example.com>; Sat, 10 Apr 2010 21:58:09 +0900 (JST)
Received: from localhost (localhost [127.0.0.1])
	by smtp.zero.jp (Postfix) with ESMTP id 11B0D48B90
	for <master@example.com>; Sat, 10 Apr 2010 21:58:05 +0900 (JST)
X-Virus-Scanned: amavisd-new at zero.jp
Received: from smtp.zero.jp ([127.0.0.1])
	by localhost (smtp.zero.jp [127.0.0.1]) (amavisd-new, port 10024)
	with ESMTP id cugPNqOlttuF for <master@example.com>;
	Sat, 10 Apr 2010 21:58:04 +0900 (JST)
Received: from [192.168.1.2] (FLH9Aab091.kng.mesh.ad.jp [218.227.160.91])
	by smtp.gmoserver.jp (Postfix) with ESMTPSA id D2DAB380CE
	for <master@example.com>; Sat, 10 Apr 2010 21:58:04 +0900 (JST)

どうやらいろいろ転送されてから目的地のSMTPサーバへたどり着くようです。これでは単純に v=spf1 +mx -all としたのでは動きません!

そこで、最後に転送しているsmtp.zero.jpをSPFレコードに追加してやることにします。しかし、よく見るとReceived: from smtp.zero.jp (smtp06.zero.jp [210.157.5.236])とかなってます。smtp.zero.jpを名乗っているけど実際にはsmtp06.zero.jpだったよということです。今回はsmtp06でしたけど将来的にもsmtp06が使われるかは怪しいところです。
しかし、あきらめる必要はありません!ありがたいことにSPFレコードにはincludeというものがあるのでこれをを使って外部参照してやればいいのです。ですが、zero.jpにSPFレコードがないと参照しても意味ありません。
ということで、ためしにdig zero.jp txtってみます。

$ dig zero.jp txt

; <<>> DiG 9.2.4 <<>> zero.jp txt
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22670
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2

;; QUESTION SECTION:
;zero.jp.                       IN      TXT

;; ANSWER SECTION:
zero.jp.                84820   IN      TXT     "v=spf1 +ip4:210.157.4.0/24 +ip4:210.172.146.0/24 +ip4:210.157.11.229 +ip4:210.157.5.0/24 +ip4:210.172.128.0/24 +ip4:210.172.129.0/24 ~all"

;; AUTHORITY SECTION:
zero.jp.                49127   IN      NS      dns1.interq.or.jp.
zero.jp.                49127   IN      NS      dns.interq.or.jp.

;; ADDITIONAL SECTION:
dns.interq.or.jp.       54590   IN      A       210.157.0.1
dns1.interq.or.jp.      7863    IN      A       210.157.0.2

;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Apr 10 22:29:10 2010
;; MSG SIZE  rcvd: 254

ちゃんとspfレコードが設定されていて、先ほどのIPも含まれているので問題なく使えそうです。

あとはv=spf1 include:zero.jp -allというSPFレコードを追加すればOK!

ためしにcheck-auth@verifier.port25.comにメールを送信してみると、下記のようになり、SPF checkがpassであることがわかります。

This message is an automatic response from Port25's authentication verifier
service at verifier.port25.com. The service allows email senders to perform
a simple check of various sender authentication mechanisms. It is provided
free of charge, in the hope that it is useful to the email community. While
it is not officially supported, we welcome any feedback you may have at
.

Thank you for using the verifier,

The Port25 Solutions, Inc. team

==========================================================
Summary of Results
==========================================================
SPF check: pass
DomainKeys check: neutral
DKIM check: neutral
Sender-ID check: pass
SpamAssassin check: ham

めでたしめでたし。

第51回PHP勉強会に行ってきました。

100回へ向けた折り返しとなる第51回PHP勉強会@関東に参加してきました。
前回の大盛況と打って変わって今回は大量のキャンセルなどにより8名分枠が余っていました。もったいない。

感想と突っ込み

CodeIgniterのUnit_testクラスとHMVC (nekogetさん)

CodeIgniterでUnitテストを見やすく実装してみたよというお話。CodeIgniterは使わないのですが、テスト結果をリアルタイムでブラウザ上で表示するというのは面白いなと思いました。
でも、そこそこ規模が大きくなってくるとテスト実行するだけで数分とか掛かるようになる気がしますが、そこんとこどうなんでしょう。と今思いました。

rhaco2(riafさん)

symfonyを賛美しながらの、racho2のゆるふわな説明でした。
僕が発表するとどうしてもガッチリやろうとしてしまうので、ああいうゆるふわな発表にはあこがれます。
rhaco2はrhacoのver.2ではなくてracho2のver.1.xだということは重要そうです。

Openpear (id:sotarokさん)

Openpearのリニューアルのための人員確保を狙ったOpenpearの中身の話でした。Openpearオープンソース化されて、中身はrhaco2だそうです。完成はまたPHPカンファレンスを目指すらしいです。
懇親会でいろいろ突っ込みを入れる予定でしたがsotarokさんが懇親会に参加しなかったので突っ込めませんでした。残念。SourceForgeだと説明文のユーザ言語版がないときには機械翻訳を表示してくれますが、Openpearも追随したら良いのになぁと帰り道で思ってました。
がんばってください。フレームワークagaviだったら手伝えたのに!

リソース指向フレームワークBEARのご紹介(TOMさん)

RESTの考え方に基づいたリソース指向という思想で作られたフレームワークの説明でした。
rhaco2のときもそうでしたが、開発者が会場にいるのに別の人が発表するのってやりづらいだろうなと思いました。
それはさておき、BEARはRESTfulな思想で作られているとか、リソースにはCRUDだけしかないからいいとか言っていましたが、agaviだってリソース指向に基づいて利用できます。
agaviではMVCのCにあたる部分がagavi本体のController,Routingと開発単位である各モジュール内にあるActionクラスが担っています。このうちActionクラスでは本質的な処理はexecuteRead,executeWrite,executeDelete,executeCreateが行います。すなわちCRUDです。
つまり、開発者がActionをリソースとして認識して実装すれば立派なリソース指向フレームワークとなりうるわけです。
また、BEARではページ層として扱っている部分をagaviではViewが担っています。ViewはViewクラスとRendererが主な処理を行いますが、さらにレイヤーやスロットといった概念を持つことにより、複数のActionをひとつの出力にまとめることなども簡単に行うことができます。さらに、agaviには出力形式(Output Type)という概念が導入されており、同じAction呼び出しに対する出力をhtmlにしたりxmlにしたり、jsonにしたりと出し分けることができます。
出力形式はコントローラのRoutingクラスの設定ファイルであるrouting.xmlによって設定することができます。例えば特定のURIに対するアクセスの返答をjsonに固定にすることや、あるいは同じURIに対するリクエストでもHTTPヘッダのAcceptにapplication/jsonが含まれていたらjsonそれ以外はhtmlというコンテントネゴシエーションを実装することが簡単にできます。それこそ、RESTfulなWebAPIと同様の機能を提供するWebアプリケーションを同じAction,Modelを使って実装することができてしまいます。
また、リソース層に封じ込めてあるのでコマンドラインから呼び出すように実装できるともおっしゃっていましたが、agaviはConsole対応しており、設定ファイルを数行いじってViewにコマンドライン用出力形式対応のメソッドを追加してあげるだけで簡単にコマンドラインから呼び出せます。本当に簡単なのでwebサーバの設定がめんどくさい*1時にコマンドライン版でMとCを実装しておいて、あとからhtml出力をViewに実装するなんてことを以前行ったことがあります。
BEARの切り口は大変面白いですが、本気MVCagaviはもっと柔軟でかつ便利です! MVCよりもリソース指向がよいと思っていたのなら、それはそこらへんのなんちゃってMVCをやってるフレームワークを見ていたからかも知れませんよ!

64bit PHPの罠(hnwさん)

64bit環境でPHPを動かしたときに起こりうる問題のお話でした。具体的にはint型が64bitになってunix timestampの範囲が地球の寿命を越えるということのようです。その結果intの最大値がfloatの最大値を上回ったり、
mysqlの0000-00-00が意味を持っちゃったりとするようです。
いま、マニュアルをみていてPHPのマニュアルに下記のような記述を発見しました。これ、64bitでPHP_INT_MAX/1とかPHP_INT_MAX/1.0とか(PHP_INT_MAX-1)/2とかPHP_INT_MAX/2とかしたらどうなっちゃうんでしょう。


PHP には整数の割り算はありません。1/2 は float 型の 0.5 になります。

謝辞

今回会場を提供してくださったトライコーン株式会社様、ありがとうございました。
また、司会兼幹事をしてくださったgusagiさん毎度お疲れ様です。

*1:加えて、html表示のデザインが上がっていなかった

HTML_Emojiを読んでみた。

昨日の続きで今日はHTML_Emojiを読んでみました。
処理は単純でUTF-8に変換したものをpreg_replace_callback使って絵文字っぽい私的領域を抜き出して連想配列のマップで置き換えるだけ!
また、ソース読んだだけでも分かりますが、作者のベンチマークによると他の変換スクリプトよりも桁違いに高速らしいです。
現在はバイナリ間の変換+PC用出力のみですが、アルゴリズム的には容易に文字数値参照にも対応できそうです。(対応してくれるかは別として)
ただ、マップ連想配列PHPコードを直接設定ファイルに書いているため絵文字対応が非常に分かりにくいです。Text_Pictogram_Mobileのようなすっきりした形から、実行時に自動生成してキャッシュするようになるといいと思いました。

Text_Pictogram_Mobileを読んでみた。

なんとなくXdebugでプロファイルをとってみたら、絵文字変換に半分以上持っていかれていたので絵文字変換を高速化したいなと思い動きだしました。
現在はMobilePictogramConverterをPHP5対応させたものを使っているのですが、他のライブラリも見ておこうと思い、絵文字変換id:Yudoufuさんがメンテしている絵文字変換ライブラリText_Pictogram_Mobileのtrunkコードを読んでみました。

基本的には下図のようなフローになっていました。

イテレータによって文字コードごとのマルチバイトの扱いと外字領域判定を吸収しています。また、1つの文字列中に複数のキャリアの絵文字が混在している状況に対応しているようで、1文字ごとにどこの絵文字か判定していました。

ざっと読んでみて、次のような問題点が分かりました。

  1. 絵文字判定がイテレータの内と外にある
  2. イテレーション前にbin2hexしているのが無駄
  3. 文字参照に非対応

また、高速化を図るのであればマルチバイト文字列のイテレータをextensionにするのがいいのかなと思いました。そうでなくても、実はmb_strlenとmb_strsubを組み合わせればもっと簡単にイテレーションできる気がします。

ところで、trunkの最後の更新が去年の1月なんですけど、開発は再開されるんですか?

第49回PHP勉強会@関東に参加してきました。

第49回PHP勉強会@関東に参加してきました。今回も遅刻しました。すみません。準備を終えて出発しようとノートパソコンをシャットダウンしようとしたらWindows Updateがあると言われてて「まぁ平気だろ」と軽いノリで実行したら32件も有って家を出られませんでした。gusagiさんのPCの調子が悪かったおかげで本編には間に合いました。ありがとうございます。

感想

Lithiumラボ Phase1 (id:yandodさん)id間違ってた

CakePHPから派生したPHP5.3用のフレームワーク名前空間や静的遅延拘束、無名関数などを利用して拡張性を高めたりしているらしいです。中でも、無名関数を利用したフィルター機能というのが新しいなと思いました。
フィルター機能とは、簡単に言うとコアクラスのメソッドに無名関数を使ってaspect指向な変更を加えられる機能のようです。

PHPでBrainF*ckとあと何か小ネタ (id:msakamoto-sf さん)

チューリングマシン的な命令の非常に少ない低レベルな言語の命令を文字や文字列に割り当てて、割り当てた以外を無視してやることで、一見ふざけた文章っぽいものをプログラムコードとして実行させるというお遊びでした。

Datasourceをオススメします (id:kaz_29 さん)

CakePHPでデータベースなんかを取り扱うDatasourceといもののお話でした。DBのみならずCSVやらRSSフィードやらほかのものも透過的に扱えるそうです。なかなか面白いものでした。
Agavi的にはそういったレイヤのものはフレームワークからはずす設計思想なのですが、周辺ライブラリとして同様の仕組みを提供するのも面白いかなと思いました。

MongoDB + PHP + CakePHP (id:ichikaway さん)

MongoDBというドキュメント指向データベースとそれをPHPから扱う方法と、CakePHP用に前述のDatasourceを作成したというお話でした。
MongoDBはスキーマレスということでRDBで言うところの行にjsonポイデータを突っ込んで検索して削除して更新するというもので、柔軟性を求められるシステムを構築する際には重宝しそうでした。また、速度もMySQLよりも断然早いらしいので、高負荷が考えられる場面での利用にも適しているようです。機会があれば使ってみたい製品だと思います。

発表資料

今回私の発表で使用した資料は「NetBeansを使ってAgaviで携帯サイトを作ってみた」でご覧になれます。

謝辞

今回、会場を提供してくださった株式会社コンテンツワン様、大変ありがとうございました。
また、司会・懇親会幹事・懇親会二次会のピエロ役をしてくださったgusagiさん、受付・会場準備をされた方お疲れ様でした。