SlideShare une entreprise Scribd logo
1  sur  78
Télécharger pour lire hors ligne
お前は PHP の歴史的な
理由の数を覚えているのか
Kousuke Ebihara (海老原昂輔)
<kousuke@co3k.org>
答
答
5 個
答
5 個
_人人人人人人人人人人_	
 
> 言うほどなかった <	
 
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄	
 
※ドキュメントから数えただけなので実体としてはもっとありそうですが、今回は考えません
自己紹介
• Kousuke Ebihara (海老原昂輔) a.k.a. @co3k
• 株式会社 VOYAGE GROUP (2014/02 より)
• スマホコミュケーション事業室で Python 書いてます
• そういえば PHP 全然書いてないです
• セキュリティ周り
• 以前は某 OSS の SNS エンジンとかその辺やってました
歴史的な理由のある機能
• implode()
• urlencode() / rawurlencode()
• double 型 / float 型 と、 gettype() の返り値
• Phar アーカイブのマニフェスト情報
• Zend Engine の HashTable (間に合わず)
調査方法
• PHP 4 以降については普通に Git で潜っていく
• php-src : 公式の Git リポジトリ
• ドキュメント: git-svn で公式のリポジトリを変換
• PHP 3 以前
• museum.php.net (かなり重いので注意)
• ML
• 1996/07 - 1998/01: PHP/FI Mailing List
• 1996/12 以降: php-internals (marc.info なら旧 php-dev 時代も追える)
implode()
implode() の歴史的な理由
• 「implode() は、歴史的な理由により、引数をどちらの順番
でも受けつけることが可能です」
• おそらく PHP で一番有名な「歴史的な理由」
implode() の実装
PHP_FUNCTION(implode)!
{!
********************** SNIP *********************!
if (arg2 == NULL) {!
********************** SNIP *********************!
} else {!
if (Z_TYPE_PP(arg1) == IS_ARRAY) {!
arr = *arg1;!
convert_to_string_ex(arg2);!
delim = *arg2;!
} else if (Z_TYPE_PP(arg2) == IS_ARRAY) {!
arr = *arg2;!
convert_to_string_ex(arg1);!
delim = *arg1;!
} else {!
********************** SNIP *********************!
}!
}!
!
php_implode(delim, arr, return_value TSRMLS_CC);
implode() の実装
PHP_FUNCTION(implode)!
{!
********************** SNIP *********************!
if (arg2 == NULL) {!
********************** SNIP *********************!
} else {!
if (Z_TYPE_PP(arg1) == IS_ARRAY) {!
arr = *arg1;!
convert_to_string_ex(arg2);!
delim = *arg2;!
} else if (Z_TYPE_PP(arg2) == IS_ARRAY) {!
arr = *arg2;!
convert_to_string_ex(arg1);!
delim = *arg1;!
} else {!
********************** SNIP *********************!
}!
}!
!
php_implode(delim, arr, return_value TSRMLS_CC);
第 2 引数が指定されている
implode() の実装
PHP_FUNCTION(implode)!
{!
********************** SNIP *********************!
if (arg2 == NULL) {!
********************** SNIP *********************!
} else {!
if (Z_TYPE_PP(arg1) == IS_ARRAY) {!
arr = *arg1;!
convert_to_string_ex(arg2);!
delim = *arg2;!
} else if (Z_TYPE_PP(arg2) == IS_ARRAY) {!
arr = *arg2;!
convert_to_string_ex(arg1);!
delim = *arg1;!
} else {!
********************** SNIP *********************!
}!
}!
!
php_implode(delim, arr, return_value TSRMLS_CC);
第 2 引数が指定されている
配列が第 1 引数に指定され
ていればデリミタは第 2 引数
implode() の実装
PHP_FUNCTION(implode)!
{!
********************** SNIP *********************!
if (arg2 == NULL) {!
********************** SNIP *********************!
} else {!
if (Z_TYPE_PP(arg1) == IS_ARRAY) {!
arr = *arg1;!
convert_to_string_ex(arg2);!
delim = *arg2;!
} else if (Z_TYPE_PP(arg2) == IS_ARRAY) {!
arr = *arg2;!
convert_to_string_ex(arg1);!
delim = *arg1;!
} else {!
********************** SNIP *********************!
}!
}!
!
php_implode(delim, arr, return_value TSRMLS_CC);
第 2 引数が指定されている
配列が第 1 引数に指定され
ていればデリミタは第 2 引数
配列が第 2 引数に指定され
ていればデリミタは第 1 引数
implode() の実装
PHP_FUNCTION(implode)!
{!
********************** SNIP *********************!
if (arg2 == NULL) {!
********************** SNIP *********************!
} else {!
if (Z_TYPE_PP(arg1) == IS_ARRAY) {!
arr = *arg1;!
convert_to_string_ex(arg2);!
delim = *arg2;!
} else if (Z_TYPE_PP(arg2) == IS_ARRAY) {!
arr = *arg2;!
convert_to_string_ex(arg1);!
delim = *arg1;!
} else {!
********************** SNIP *********************!
}!
}!
!
php_implode(delim, arr, return_value TSRMLS_CC);
第 2 引数が指定されている
配列が第 1 引数に指定され
ていればデリミタは第 2 引数
配列が第 2 引数に指定され
ていればデリミタは第 1 引数
配列が指定されていなければ
エラー
implode() の歴史
• PHP/FI 2 には implode() も explode() も存在しない
• PHP 3 にはある
• PHP 3 時点では implode() は現在と同じ挙動に
• つまりこの「歴史的な理由」は PHP/FI 2 → PHP 3 の開
発中に生まれたものと思われる
PHP 3.0a3
(November 23 1997)
• Switched between the 1st and 2nd parameters to
explode(), so that it acts like split()

(拙訳: explode() の第 1 引数と第 2 引数を交換したの
で、 split() と同じように動作するようになりました)
split() と explode()
split() と explode()
元々は逆 (implode() が歴史的な理由により受け付ける順序と同じ�)
PHP 3.0b5
(February 24 1998)
• Made implode() accept arguments in the order
used by explode() as well

(拙訳: implode() が explode() で使われているような引
数順も受け付けるようにしました)
explode() と implode() に
何が起こったか
• PHP 3.0 開発中に explode(), implode(), split() が追加された
• このタイミングで追加、変更された機能は多いので当時の CHANGELOG を眺めているだけでも結構楽しい
• PHP 3.0a3 にて、 explode() の引数順を split() に合わせた
• この結果、 implode() との統一性が取れなくなったので、PHP
3.0b5 にて、 implode() では両方の引数順を受け付けるようにした
• explode() が据え置きだったのは、引数が両方とも文字列型だから?
• わずか 3 ヶ月の「歴史」
urlencode() / rawurlencode()
URL エンコード用の 2 つの関数
• urlencode()
• 文字列を URL エンコード
• rawurlencode()
• 文字列を URL エンコード
URL エンコード用の 2 つの関数
• urlencode()
• 文字列を URL エンコード
• rawurlencode()
• 文字列を URL エンコード
(RFC 3986 に基づかない)
URL エンコード用の 2 つの関数
• urlencode()
• 文字列を URL エンコード
• rawurlencode()
• 文字列を URL エンコード
(RFC 3986 に基づかない)
(RFC 3986 に基づく)
どのような違いがあるか?
• urlencode()
• 空白 (U+0020) を + (U+003B) に置き換える
• ~ (U+007E) をエンコードする (RFC 1738 に基づく)
• rawurlencode()
• 空白 (U+0020) をパーセントエンコードする
• ~ (U+007E) をエンコードしない (RFC 3986 に基づく)
どのような違いがあるか?
• urlencode()
• 空白 (U+0020) を + (U+003B) に置き換える
• ~ (U+007E) をエンコードする (RFC 1738 に基づく)
• rawurlencode()
• 空白 (U+0020) をパーセントエンコードする
• ~ (U+007E) をエンコードしない (RFC 3986 に基づく)
追従漏れじゃね……?
urlencode() の歴史的な理由
• 「歴史的な理由により、この関数は RFC 3986 エンコード
(rawurlencode() を参照してください) とは異なり、空白を
+ 記号にエンコードします」
urlencode() の実装
(EBCDIC モード時の処理は省略)
PHPAPI char *php_url_encode(char const *s, int len, int
*new_length)!
{!
********************** SNIP *********************!
while (from < end) {!
c = *from++;!
!
if (c == ' ') {!
*to++ = '+';!
} else if ((c < '0' && c != '-' && c != '.') ||!
(c < 'A' && c > '9') ||!
(c > 'Z' && c < 'a' && c != '_') ||!
(c > 'z')) {!
to[0] = '%';!
to[1] = hexchars[c >> 4];!
to[2] = hexchars[c & 15];!
to += 3;!
} else {!
*to++ = c;!
}!
}
urlencode() の実装
(EBCDIC モード時の処理は省略)
PHPAPI char *php_url_encode(char const *s, int len, int
*new_length)!
{!
********************** SNIP *********************!
while (from < end) {!
c = *from++;!
!
if (c == ' ') {!
*to++ = '+';!
} else if ((c < '0' && c != '-' && c != '.') ||!
(c < 'A' && c > '9') ||!
(c > 'Z' && c < 'a' && c != '_') ||!
(c > 'z')) {!
to[0] = '%';!
to[1] = hexchars[c >> 4];!
to[2] = hexchars[c & 15];!
to += 3;!
} else {!
*to++ = c;!
}!
}
while ループで文字列終端まで from
を 1 文字ずつ走査
urlencode() の実装
(EBCDIC モード時の処理は省略)
PHPAPI char *php_url_encode(char const *s, int len, int
*new_length)!
{!
********************** SNIP *********************!
while (from < end) {!
c = *from++;!
!
if (c == ' ') {!
*to++ = '+';!
} else if ((c < '0' && c != '-' && c != '.') ||!
(c < 'A' && c > '9') ||!
(c > 'Z' && c < 'a' && c != '_') ||!
(c > 'z')) {!
to[0] = '%';!
to[1] = hexchars[c >> 4];!
to[2] = hexchars[c & 15];!
to += 3;!
} else {!
*to++ = c;!
}!
}
while ループで文字列終端まで from
を 1 文字ずつ走査
スペースを + に置換して to に格納
urlencode() の実装
(EBCDIC モード時の処理は省略)
PHPAPI char *php_url_encode(char const *s, int len, int
*new_length)!
{!
********************** SNIP *********************!
while (from < end) {!
c = *from++;!
!
if (c == ' ') {!
*to++ = '+';!
} else if ((c < '0' && c != '-' && c != '.') ||!
(c < 'A' && c > '9') ||!
(c > 'Z' && c < 'a' && c != '_') ||!
(c > 'z')) {!
to[0] = '%';!
to[1] = hexchars[c >> 4];!
to[2] = hexchars[c & 15];!
to += 3;!
} else {!
*to++ = c;!
}!
}
while ループで文字列終端まで from
を 1 文字ずつ走査
スペースを + に置換して to に格納
それ以外のエンコード対象の文字は
パーセントエンコードして to に格納
urlencode() の実装
(EBCDIC モード時の処理は省略)
PHPAPI char *php_url_encode(char const *s, int len, int
*new_length)!
{!
********************** SNIP *********************!
while (from < end) {!
c = *from++;!
!
if (c == ' ') {!
*to++ = '+';!
} else if ((c < '0' && c != '-' && c != '.') ||!
(c < 'A' && c > '9') ||!
(c > 'Z' && c < 'a' && c != '_') ||!
(c > 'z')) {!
to[0] = '%';!
to[1] = hexchars[c >> 4];!
to[2] = hexchars[c & 15];!
to += 3;!
} else {!
*to++ = c;!
}!
}
while ループで文字列終端まで from
を 1 文字ずつ走査
スペースを + に置換して to に格納
それ以外のエンコード対象の文字は
パーセントエンコードして to に格納
エンコードしない文字はそのまま
to に格納
PHPAPI char *php_raw_url_encode(char const *s, int len, int
*new_length)!
{!
register int x, y;!
unsigned char *str;!
!
str = (unsigned char *) safe_emalloc(3, len, 1);!
for (x = 0, y = 0; len--; x++, y++) {!
str[y] = (unsigned char) s[x];!
if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||!
(str[y] < 'A' && str[y] > '9') ||!
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||!
(str[y] > 'z' && str[y] != '~')) {!
str[y++] = '%';!
str[y++] = hexchars[(unsigned char) s[x] >> 4];!
str[y] = hexchars[(unsigned char) s[x] & 15];!
}!
}
rawurlencode() の実装
(EBCDIC モード時の処理は省略)
PHPAPI char *php_raw_url_encode(char const *s, int len, int
*new_length)!
{!
register int x, y;!
unsigned char *str;!
!
str = (unsigned char *) safe_emalloc(3, len, 1);!
for (x = 0, y = 0; len--; x++, y++) {!
str[y] = (unsigned char) s[x];!
if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||!
(str[y] < 'A' && str[y] > '9') ||!
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||!
(str[y] > 'z' && str[y] != '~')) {!
str[y++] = '%';!
str[y++] = hexchars[(unsigned char) s[x] >> 4];!
str[y] = hexchars[(unsigned char) s[x] & 15];!
}!
}
rawurlencode() の実装
(EBCDIC モード時の処理は省略)
for ループで文字列終端まで 1 文字
ずつ走査
PHPAPI char *php_raw_url_encode(char const *s, int len, int
*new_length)!
{!
register int x, y;!
unsigned char *str;!
!
str = (unsigned char *) safe_emalloc(3, len, 1);!
for (x = 0, y = 0; len--; x++, y++) {!
str[y] = (unsigned char) s[x];!
if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||!
(str[y] < 'A' && str[y] > '9') ||!
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||!
(str[y] > 'z' && str[y] != '~')) {!
str[y++] = '%';!
str[y++] = hexchars[(unsigned char) s[x] >> 4];!
str[y] = hexchars[(unsigned char) s[x] & 15];!
}!
}
rawurlencode() の実装
(EBCDIC モード時の処理は省略)
for ループで文字列終端まで 1 文字
ずつ走査
とりあえず str に文字を格納
PHPAPI char *php_raw_url_encode(char const *s, int len, int
*new_length)!
{!
register int x, y;!
unsigned char *str;!
!
str = (unsigned char *) safe_emalloc(3, len, 1);!
for (x = 0, y = 0; len--; x++, y++) {!
str[y] = (unsigned char) s[x];!
if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||!
(str[y] < 'A' && str[y] > '9') ||!
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||!
(str[y] > 'z' && str[y] != '~')) {!
str[y++] = '%';!
str[y++] = hexchars[(unsigned char) s[x] >> 4];!
str[y] = hexchars[(unsigned char) s[x] & 15];!
}!
}
rawurlencode() の実装
(EBCDIC モード時の処理は省略)
for ループで文字列終端まで 1 文字
ずつ走査
エンコード対象の文字ならパーセントエンコード
とりあえず str に文字を格納
(つд⊂)ゴシゴシゴシ
(;゚Д゚)	
 共通化されてねぇ……!
なぜ空白を + に置き換えるか
技術/HTTP/URLエンコードで 0x20(スペース) を "+" にすべきか "%20" にすべきか - Glamenv-Septzen.net

http://www.glamenv-septzen.net/view/1170

※PHP に関する記述 (rawurlencode() が用意された経緯など) は若干事実と異なる部分がある。本スライドで詳述
なぜ空白を + に置き換えるか
• application/x-www-form-urlencoded のため
• W3C の規格 (たとえば HTML 5) などに含まれる (単独の
規格は存在しない)
• form が submit された場合のレスポンスボディのエンコー
ド方式
• 空白を + に置き換えるほかはだいたいパーセントエンコード
他の言語の状況
• Python 2 (Python 3 では urllib.parse)
• RFC 3986 の URL エンコード: urllib.quote()
• application/x-www-form-urlencoded: urllib.quote_plus()
• Ruby
• RFC 3986 の URL エンコード: ERB::Util.u(), URI.encode()
• application/x-www-form-urlencoded: URI.encode_www_form(),
CGI.escape()
• ただし URI.encode() は obsolete で、 ERB::Util.u() とかが代替となっている模
様
urlencode() の歴史
• PHP/FI 2.0 から存在
• この当時から空白 (U+0020) を + (U+003B) に置き
換える実装になっていた
char *php_urlencode(char *s) {!
********************** SNIP *********************!
for(x=0,y=0; s[x]; x++,y++) {!
str[y] = s[x];!
if(str[y]==' ') {!
str[y]='+';
rawurlencode() の歴史
• PHP 3.0b3 から存在 (当時は RFC 1738 ベース)
• まーた PHP 3.0 か!
• RFC 3986 は 2005 年 1 月
• PHP 3.0 は 1999 年 (PHP 3.0b3 は 1998 年)
• PHP 5.0 のタイミングで RFC 3986 ベースに変更
rawurlencode() 誕生秘話
(序章)
• 1997/06/16 (PHP/FI 2.0b12)
• UrlEncode() がスペースを + に置換するようになる
• 1997/11/12 (PHP/FI 2.0)
• UrlEncode() が / をエンコードしないようになる (後に撤
回)
• URL 文字列全体のエンコードを意図した
議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2
rawurlencode() 誕生秘話
(事件篇)
• 1998/01/15 頃 (PHP 3.0b3 開発中)
• Jaakko Hyvätti が urlencode() で & をエンコードしないように変
更? (意図の説明を user ML にポストしたようだが入手できず)
• PHP/FI 2.0 での変更の意図に合わせたもの
• おそらくここで rawurlencode() と formencode() (おそらくリリー
ス前に削除) が入ったと思われる ([PHP-DEV] ML で my
rawurlencode() などと説明しているので)
• PHP 3.0b3-dev の urlencode() が壊れたと報告がくる
議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2
rawurlencode() 誕生秘話
(解決篇)
• 1998/01/16
• PHP 2.0 の変更が不適切ということになり、スペースを + に置換する版まで戻される
• ちなみに Jaakko は「rawurl*code() っていい名前ない?�urlpath*code() とか?」
とも言ってるが Rasmus 華麗にこれをスルー
• スペースを + にする件も戻した方がいいのでは、という Jaakko の提案に Rasmus
は反対
• 「スペースが + になっていれば urldecode() なしで POST data が使える」、
「URL 中の + は自動的にスペースにデコードされる」(= つまり + なら URL と
POST data どっちもいける)
• 既存のコードが壊れる
議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2
urlencode() と rawurlencode()
についてのまとめ
• URL 中の文字列のエンコードをおこなう際は、
rawurlencode() を使ったほうがよい
• urlencode() を使うべき場面は滅多にない
• 名前的に urlencode() の方が正しそうなので多用されがち
だが……
• 自力で POST データのエンコードをしたい場合くらい
• そもそも RFC�3986 にも追従していない
問題のあった事例
• Bug(バグ) #3383: mail_to 関数を用いるときに空白が
+ に変換されてしまう - OpenPNE 3

https://redmine.openpne.jp/issues/3383
• ここで気がついた (symfony の link_to() は
urlencode() を使っている)
• 空白を意図して渡していても + をスペースに展開しない
メーラがあったと思われる
DOUBLE 型と FLOAT 型
PHP における浮動小数点数
• 精度は環境依存だが、通常 IEEE 754 の double (倍精度
浮動小数点数)
• PHP では float 型ということで統一されている
• 型キャストの際に (double) や (real) しても float にな
る
浮動小数点数の (?)
歴史的な理由
• 「double は float と同じものだと考えてください。 2 種類
の名前が存在するのは、歴史的な理由によるものです」
float / double 型の歴史
• PHP/FI 2.0 (1997/11/12) : double
• PHP 3.0 (1998/06/06) : double (float, real でもキャスト
できるように)
• PHP 4.1.0 (2001/12/10): float……?
• 2c275bf793f70ad2a38bbf4a0f7ad12fecaca095,
03f7406711d3706af0f237e1ea03974616dd2139
など
なんで double -> float に
なったか
• 不明……
• ML では議論されてない?
• 突如として float 派が出現したように見える [要出典]
• 無理に double を float に置換する必要があったのかどう
か疑問
float 派の闘いの記録
• Hartmut Holzgraefe
• double -> float への置換をおこなった最初の人物
• 多くの double -> float の置換に貢献
• Jeroen van Wolffelaar
• ドキュメントに存在するほとんどの double を float に置換した
• Gabor Hojtsy
float 派の登場
• Hartmut Holzgraefe による 2001/09/21 のコミット
(2c275bf7) で、 floatval(), is_float() のエイリアスとし
て doubleval(), is_double() を使うように変更 (それまで
は逆)
• さらに (03f74067) で関数定義部分のコメント (返り値や
引数型などが書かれている) の double を float に置換
float 派の登場
新たな double の出現
float 派の反撃
php has no ‘double’, only ’float’
しかし止まらない double の追加
そして 1 年が経ったある日
“php has no ‘double’” とはなんだったのか
ドキュメントの置換も忘れない
• r53773 (2001/08/07) by Jeroen van Wolffelaar
• r54456 (2001/08/12) by Jeroen van Wolffelaar
• r54918 (2001/08/14) by Jeroen van Wolffelaar
• r57972 (2001/09/21) by Hartmut Holzgraefe
• r57997 (2001/09/21) by Jeroen van Wolffelaar
• r57999 (2001/09/21) by Jeroen van Wolffelaar
ぜんぶ歴史のせいだ。
未だ残る double の痕跡
• 「歴史的な理由により、 float の場合には “double” が返
されます。 “float” とはなりません」
Phar アーカイブのマニフェスト情報
Phar アーカイブのマニフェスト
情報における歴史的な理由
• 「Phar マニフェストは高度に最適化された書式で (略) 1
バイトをこえる大きさの値はリトルエンディアン形式のバイト
順で保存されます。ただし API バージョンだけは例外です。
これは 3 ニブルのデータですが、歴史的な理由によりビッ
グエンディアン形式のバイト順で保存されます」
Phar アーカイブの構造
スタブ
マニフェスト
コンテンツ
シグネチャ (optional)
Phar アーカイブの構造
スタブ
マニフェスト
コンテンツ
シグネチャ (optional)
Phar アーカイブの起動時に実行される
PHP スクリプト。
__HALT_COMPILER(); で終了
Phar アーカイブの構造
スタブ
マニフェスト
コンテンツ
シグネチャ (optional)
Phar アーカイブの起動時に実行される
PHP スクリプト。
__HALT_COMPILER(); で終了
バージョン情報などのメタ情報
Phar アーカイブの構造
スタブ
マニフェスト
コンテンツ
シグネチャ (optional)
Phar アーカイブの起動時に実行される
PHP スクリプト。
__HALT_COMPILER(); で終了
バージョン情報などのメタ情報
アーカイブの内容
Phar アーカイブの構造
スタブ
マニフェスト
コンテンツ
シグネチャ (optional)
Phar アーカイブの起動時に実行される
PHP スクリプト。
__HALT_COMPILER(); で終了
バージョン情報などのメタ情報
アーカイブの内容
パッケージ検証用のシグネチャ。
Phar 形式のみ
Phar アーカイブのマニフェスト
マニフェストの長さ
(Little Endian)
格納するファイルの数
(Little Endian)
ビットマップフラグ
(Little Endian)
API バージョン
(Big Endian)
エイリアスの長さ
(Little Endian)
エイリアス
(※任意桁)
…
メタデータの長さ
(Little Endian)
メタデータ
(※任意桁)
…
ファイルのリスト
(※任意桁)
…
Phar アーカイブのマニフェスト
マニフェストの長さ
(Little Endian)
格納するファイルの数
(Little Endian)
ビットマップフラグ
(Little Endian)
API バージョン
(Big Endian)
エイリアスの長さ
(Little Endian)
エイリアス
(※任意桁)
…
メタデータの長さ
(Little Endian)
メタデータ
(※任意桁)
…
ファイルのリスト
(※任意桁)
…
ニブル単位でバージョンを表現
Phar アーカイブのマニフェスト
マニフェストの長さ
(Little Endian)
格納するファイルの数
(Little Endian)
ビットマップフラグ
(Little Endian)
API バージョン
(Big Endian)
エイリアスの長さ
(Little Endian)
エイリアス
(※任意桁)
…
メタデータの長さ
(Little Endian)
メタデータ
(※任意桁)
…
ファイルのリスト
(※任意桁)
…
ニブル単位でバージョンを表現 検証用のシグネチャが含まれて
いるか、圧縮されたファイルが存
在するかなどのフラグ
Phar アーカイブのマニフェスト
(composer.phar (1.0.0-alpha8) の例)
0x17F-82 : マニフェストの長さ (26489)
0x183-86 : ファイル数 (322)
0x187-88: API バージョン (1.1.0)
※最後の 4bit は未使用
0x189-8C : ビットマップフラグ
(0x00010000 : この Phar には検証用シグネチャが含まれる)
0x18D-90 : この Phar のエイリアスの長さ (13)
0x191-9D : エイリアス (composer.phar)
バージョン情報のみ
ビッグエンディアンである理由
• 3842b67 には元になった PHP_Archive に由来する理由とある
• PHP_Archive の最新の実装もバージョン情報だけビッグエンディアンで格納している
(PHP_Archive_Creator::serializeManifest())
• PHP_Archive の 2f41f8f48 ではアーカイブ作成時にビッグエンディアンで格納
しているが、展開時にはリトルエンディアンでパースしようとしている
• PHP_Archive の 8931abf6 で展開時にもビッグエンディアンでパースするよう修
正された
• つまり、間違えてビッグエンディアンで格納してしまったために後に引けなくなった
のでは……
ZEND ENGINE の HASHTABLE
Zend Engine の HashTable
API における歴史的な理由
• 「hash exists for historical reasons and is always
ignored」

(拙訳: 引数 hash は歴史的な理由のために存在し、常に
無視される)
Zend Engine の HashTable
API における歴史的な理由
• 時間切れで追い切れず
• まあなんとなくわかる
まとめ
• 身近な機能とかを深追いしていくのは結構楽しい
• PHP 3.0 時代のチェンジログと ML は本当にオススメ
• たとえば「昔の PHP は + 演算子で文字列結合できたんだよー」と
か無駄知識を披露してドヤ顔できる
• 5 個がっつり深追いしていくだけでも結構時間が埋まるので助かった
• Phar とか Zend Engine 周りの歴史的な理由が出てきたおかげで割
と闇 PHP っぽくなった気がする

Contenu connexe

Tendances

20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチンyohhoy
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミングPreferred Networks
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Masahito Zembutsu
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)Takeshi Yamamuro
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解MITSUNARI Shigeo
 
冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safeKumazaki Hiroki
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexprGenya Murakami
 
Xbyakの紹介とその周辺
Xbyakの紹介とその周辺Xbyakの紹介とその周辺
Xbyakの紹介とその周辺MITSUNARI Shigeo
 
ダブル配列の実装方法
ダブル配列の実装方法ダブル配列の実装方法
ダブル配列の実装方法Higashiyama Masahiko
 
JVMのGCアルゴリズムとチューニング
JVMのGCアルゴリズムとチューニングJVMのGCアルゴリズムとチューニング
JVMのGCアルゴリズムとチューニング佑哉 廣岡
 
std::pin の勘所
std::pin の勘所std::pin の勘所
std::pin の勘所Hiroaki Goto
 
マーク&スイープ勉強会
マーク&スイープ勉強会マーク&スイープ勉強会
マーク&スイープ勉強会7shi
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回Tomoya Kawanishi
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話Kumazaki Hiroki
 

Tendances (20)

20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミング
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解
 
URLで遊ぼう
URLで遊ぼうURLで遊ぼう
URLで遊ぼう
 
冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safe
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
 
Xbyakの紹介とその周辺
Xbyakの紹介とその周辺Xbyakの紹介とその周辺
Xbyakの紹介とその周辺
 
ダブル配列の実装方法
ダブル配列の実装方法ダブル配列の実装方法
ダブル配列の実装方法
 
JVMのGCアルゴリズムとチューニング
JVMのGCアルゴリズムとチューニングJVMのGCアルゴリズムとチューニング
JVMのGCアルゴリズムとチューニング
 
std::pin の勘所
std::pin の勘所std::pin の勘所
std::pin の勘所
 
マーク&スイープ勉強会
マーク&スイープ勉強会マーク&スイープ勉強会
マーク&スイープ勉強会
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
明日使えないすごいビット演算
明日使えないすごいビット演算明日使えないすごいビット演算
明日使えないすごいビット演算
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話
 

Similaire à お前は PHP の歴史的な理由の数を覚えているのか

C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competitionyak1ex
 
PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptxNAIST
 
PBL1-v1-007j.pptx
PBL1-v1-007j.pptxPBL1-v1-007j.pptx
PBL1-v1-007j.pptxNAIST
 
2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talkmitamex4u
 
CUDAを利用したPIV解析の高速化
CUDAを利用したPIV解析の高速化CUDAを利用したPIV解析の高速化
CUDAを利用したPIV解析の高速化翔新 史
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門natrium11321
 
Write good parser in perl
Write good parser in perlWrite good parser in perl
Write good parser in perlJiro Nishiguchi
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングKiwamu Okabe
 
PBL1-v1-003j.pptx
PBL1-v1-003j.pptxPBL1-v1-003j.pptx
PBL1-v1-003j.pptxNAIST
 
PBL1-v1-008j.pptx
PBL1-v1-008j.pptxPBL1-v1-008j.pptx
PBL1-v1-008j.pptxNAIST
 
Brief introduction of Boost.ICL
Brief introduction of Boost.ICLBrief introduction of Boost.ICL
Brief introduction of Boost.ICLyak1ex
 
x86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNTx86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNTtakesako
 
知って得するC#
知って得するC#知って得するC#
知って得するC#Shota Baba
 
拡張ライブラリ作成による高速化
拡張ライブラリ作成による高速化拡張ライブラリ作成による高速化
拡張ライブラリ作成による高速化Kazunori Jo
 
ScalableCore system at SWoPP2010 BoF-2
ScalableCore system at SWoPP2010 BoF-2ScalableCore system at SWoPP2010 BoF-2
ScalableCore system at SWoPP2010 BoF-2Shinya Takamaeda-Y
 
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competitionyak1ex
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)ryos36
 

Similaire à お前は PHP の歴史的な理由の数を覚えているのか (20)

C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
 
PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptx
 
PBL1-v1-007j.pptx
PBL1-v1-007j.pptxPBL1-v1-007j.pptx
PBL1-v1-007j.pptx
 
2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk
 
CUDAを利用したPIV解析の高速化
CUDAを利用したPIV解析の高速化CUDAを利用したPIV解析の高速化
CUDAを利用したPIV解析の高速化
 
ILE-RPG Study 001
ILE-RPG Study 001ILE-RPG Study 001
ILE-RPG Study 001
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
Write good parser in perl
Write good parser in perlWrite good parser in perl
Write good parser in perl
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
 
PBL1-v1-003j.pptx
PBL1-v1-003j.pptxPBL1-v1-003j.pptx
PBL1-v1-003j.pptx
 
PBL1-v1-008j.pptx
PBL1-v1-008j.pptxPBL1-v1-008j.pptx
PBL1-v1-008j.pptx
 
Brief introduction of Boost.ICL
Brief introduction of Boost.ICLBrief introduction of Boost.ICL
Brief introduction of Boost.ICL
 
x86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNTx86x64 SSE4.2 POPCNT
x86x64 SSE4.2 POPCNT
 
知って得するC#
知って得するC#知って得するC#
知って得するC#
 
拡張ライブラリ作成による高速化
拡張ライブラリ作成による高速化拡張ライブラリ作成による高速化
拡張ライブラリ作成による高速化
 
ScalableCore system at SWoPP2010 BoF-2
ScalableCore system at SWoPP2010 BoF-2ScalableCore system at SWoPP2010 BoF-2
ScalableCore system at SWoPP2010 BoF-2
 
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
 
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
 

Plus de Kousuke Ebihara

XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...
XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...
XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...Kousuke Ebihara
 
Let's creating your own PHP (tejimaya version)
Let's creating your own PHP (tejimaya version)Let's creating your own PHP (tejimaya version)
Let's creating your own PHP (tejimaya version)Kousuke Ebihara
 
Using Symfony Templating On Symfony 1
Using Symfony Templating On Symfony 1Using Symfony Templating On Symfony 1
Using Symfony Templating On Symfony 1Kousuke Ebihara
 
Introduction of symfony development process & What's symfony 1.3?
Introduction of symfony development process & What's symfony 1.3?Introduction of symfony development process & What's symfony 1.3?
Introduction of symfony development process & What's symfony 1.3?Kousuke Ebihara
 
OAuthで気持ちのいい アクセス制御を
OAuthで気持ちのいいアクセス制御をOAuthで気持ちのいいアクセス制御を
OAuthで気持ちのいい アクセス制御をKousuke Ebihara
 
Php5.3ってなんなんだー
Php5.3ってなんなんだーPhp5.3ってなんなんだー
Php5.3ってなんなんだーKousuke Ebihara
 
ルーティングを使って シンプルなアプリケーション開発を
ルーティングを使ってシンプルなアプリケーション開発をルーティングを使ってシンプルなアプリケーション開発を
ルーティングを使って シンプルなアプリケーション開発をKousuke Ebihara
 

Plus de Kousuke Ebihara (9)

XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...
XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...
XML と PHP のイケナイ関係 (セキュリティ的な意味で) -Introduction of XXE attack and XML Bomb with...
 
Open pne3 with_symfony
Open pne3 with_symfonyOpen pne3 with_symfony
Open pne3 with_symfony
 
Let's creating your own PHP (tejimaya version)
Let's creating your own PHP (tejimaya version)Let's creating your own PHP (tejimaya version)
Let's creating your own PHP (tejimaya version)
 
Hybrid Onboarding
Hybrid OnboardingHybrid Onboarding
Hybrid Onboarding
 
Using Symfony Templating On Symfony 1
Using Symfony Templating On Symfony 1Using Symfony Templating On Symfony 1
Using Symfony Templating On Symfony 1
 
Introduction of symfony development process & What's symfony 1.3?
Introduction of symfony development process & What's symfony 1.3?Introduction of symfony development process & What's symfony 1.3?
Introduction of symfony development process & What's symfony 1.3?
 
OAuthで気持ちのいい アクセス制御を
OAuthで気持ちのいいアクセス制御をOAuthで気持ちのいいアクセス制御を
OAuthで気持ちのいい アクセス制御を
 
Php5.3ってなんなんだー
Php5.3ってなんなんだーPhp5.3ってなんなんだー
Php5.3ってなんなんだー
 
ルーティングを使って シンプルなアプリケーション開発を
ルーティングを使ってシンプルなアプリケーション開発をルーティングを使ってシンプルなアプリケーション開発を
ルーティングを使って シンプルなアプリケーション開発を
 

Dernier

自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineerYuki Kikuchi
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)Hiroshi Tomioka
 
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?akihisamiyanaga1
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NTT DATA Technology & Innovation
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...博三 太田
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)UEHARA, Tetsutaro
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfFumieNakayama
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfFumieNakayama
 

Dernier (8)

自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
 

お前は PHP の歴史的な理由の数を覚えているのか

  • 2.
  • 4. 答 5 個 _人人人人人人人人人人_ > 言うほどなかった <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄ ※ドキュメントから数えただけなので実体としてはもっとありそうですが、今回は考えません
  • 5. 自己紹介 • Kousuke Ebihara (海老原昂輔) a.k.a. @co3k • 株式会社 VOYAGE GROUP (2014/02 より) • スマホコミュケーション事業室で Python 書いてます • そういえば PHP 全然書いてないです • セキュリティ周り • 以前は某 OSS の SNS エンジンとかその辺やってました
  • 6. 歴史的な理由のある機能 • implode() • urlencode() / rawurlencode() • double 型 / float 型 と、 gettype() の返り値 • Phar アーカイブのマニフェスト情報 • Zend Engine の HashTable (間に合わず)
  • 7. 調査方法 • PHP 4 以降については普通に Git で潜っていく • php-src : 公式の Git リポジトリ • ドキュメント: git-svn で公式のリポジトリを変換 • PHP 3 以前 • museum.php.net (かなり重いので注意) • ML • 1996/07 - 1998/01: PHP/FI Mailing List • 1996/12 以降: php-internals (marc.info なら旧 php-dev 時代も追える)
  • 9. implode() の歴史的な理由 • 「implode() は、歴史的な理由により、引数をどちらの順番 でも受けつけることが可能です」 • おそらく PHP で一番有名な「歴史的な理由」
  • 10. implode() の実装 PHP_FUNCTION(implode)! {! ********************** SNIP *********************! if (arg2 == NULL) {! ********************** SNIP *********************! } else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {! ********************** SNIP *********************! }! }! ! php_implode(delim, arr, return_value TSRMLS_CC);
  • 11. implode() の実装 PHP_FUNCTION(implode)! {! ********************** SNIP *********************! if (arg2 == NULL) {! ********************** SNIP *********************! } else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {! ********************** SNIP *********************! }! }! ! php_implode(delim, arr, return_value TSRMLS_CC); 第 2 引数が指定されている
  • 12. implode() の実装 PHP_FUNCTION(implode)! {! ********************** SNIP *********************! if (arg2 == NULL) {! ********************** SNIP *********************! } else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {! ********************** SNIP *********************! }! }! ! php_implode(delim, arr, return_value TSRMLS_CC); 第 2 引数が指定されている 配列が第 1 引数に指定され ていればデリミタは第 2 引数
  • 13. implode() の実装 PHP_FUNCTION(implode)! {! ********************** SNIP *********************! if (arg2 == NULL) {! ********************** SNIP *********************! } else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {! ********************** SNIP *********************! }! }! ! php_implode(delim, arr, return_value TSRMLS_CC); 第 2 引数が指定されている 配列が第 1 引数に指定され ていればデリミタは第 2 引数 配列が第 2 引数に指定され ていればデリミタは第 1 引数
  • 14. implode() の実装 PHP_FUNCTION(implode)! {! ********************** SNIP *********************! if (arg2 == NULL) {! ********************** SNIP *********************! } else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {! ********************** SNIP *********************! }! }! ! php_implode(delim, arr, return_value TSRMLS_CC); 第 2 引数が指定されている 配列が第 1 引数に指定され ていればデリミタは第 2 引数 配列が第 2 引数に指定され ていればデリミタは第 1 引数 配列が指定されていなければ エラー
  • 15. implode() の歴史 • PHP/FI 2 には implode() も explode() も存在しない • PHP 3 にはある • PHP 3 時点では implode() は現在と同じ挙動に • つまりこの「歴史的な理由」は PHP/FI 2 → PHP 3 の開 発中に生まれたものと思われる
  • 16. PHP 3.0a3 (November 23 1997) • Switched between the 1st and 2nd parameters to explode(), so that it acts like split()
 (拙訳: explode() の第 1 引数と第 2 引数を交換したの で、 split() と同じように動作するようになりました)
  • 18. split() と explode() 元々は逆 (implode() が歴史的な理由により受け付ける順序と同じ�)
  • 19. PHP 3.0b5 (February 24 1998) • Made implode() accept arguments in the order used by explode() as well
 (拙訳: implode() が explode() で使われているような引 数順も受け付けるようにしました)
  • 20. explode() と implode() に 何が起こったか • PHP 3.0 開発中に explode(), implode(), split() が追加された • このタイミングで追加、変更された機能は多いので当時の CHANGELOG を眺めているだけでも結構楽しい • PHP 3.0a3 にて、 explode() の引数順を split() に合わせた • この結果、 implode() との統一性が取れなくなったので、PHP 3.0b5 にて、 implode() では両方の引数順を受け付けるようにした • explode() が据え置きだったのは、引数が両方とも文字列型だから? • わずか 3 ヶ月の「歴史」
  • 22. URL エンコード用の 2 つの関数 • urlencode() • 文字列を URL エンコード • rawurlencode() • 文字列を URL エンコード
  • 23. URL エンコード用の 2 つの関数 • urlencode() • 文字列を URL エンコード • rawurlencode() • 文字列を URL エンコード (RFC 3986 に基づかない)
  • 24. URL エンコード用の 2 つの関数 • urlencode() • 文字列を URL エンコード • rawurlencode() • 文字列を URL エンコード (RFC 3986 に基づかない) (RFC 3986 に基づく)
  • 25. どのような違いがあるか? • urlencode() • 空白 (U+0020) を + (U+003B) に置き換える • ~ (U+007E) をエンコードする (RFC 1738 に基づく) • rawurlencode() • 空白 (U+0020) をパーセントエンコードする • ~ (U+007E) をエンコードしない (RFC 3986 に基づく)
  • 26. どのような違いがあるか? • urlencode() • 空白 (U+0020) を + (U+003B) に置き換える • ~ (U+007E) をエンコードする (RFC 1738 に基づく) • rawurlencode() • 空白 (U+0020) をパーセントエンコードする • ~ (U+007E) をエンコードしない (RFC 3986 に基づく) 追従漏れじゃね……?
  • 27. urlencode() の歴史的な理由 • 「歴史的な理由により、この関数は RFC 3986 エンコード (rawurlencode() を参照してください) とは異なり、空白を + 記号にエンコードします」
  • 28. urlencode() の実装 (EBCDIC モード時の処理は省略) PHPAPI char *php_url_encode(char const *s, int len, int *new_length)! {! ********************** SNIP *********************! while (from < end) {! c = *from++;! ! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! }
  • 29. urlencode() の実装 (EBCDIC モード時の処理は省略) PHPAPI char *php_url_encode(char const *s, int len, int *new_length)! {! ********************** SNIP *********************! while (from < end) {! c = *from++;! ! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! } while ループで文字列終端まで from を 1 文字ずつ走査
  • 30. urlencode() の実装 (EBCDIC モード時の処理は省略) PHPAPI char *php_url_encode(char const *s, int len, int *new_length)! {! ********************** SNIP *********************! while (from < end) {! c = *from++;! ! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! } while ループで文字列終端まで from を 1 文字ずつ走査 スペースを + に置換して to に格納
  • 31. urlencode() の実装 (EBCDIC モード時の処理は省略) PHPAPI char *php_url_encode(char const *s, int len, int *new_length)! {! ********************** SNIP *********************! while (from < end) {! c = *from++;! ! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! } while ループで文字列終端まで from を 1 文字ずつ走査 スペースを + に置換して to に格納 それ以外のエンコード対象の文字は パーセントエンコードして to に格納
  • 32. urlencode() の実装 (EBCDIC モード時の処理は省略) PHPAPI char *php_url_encode(char const *s, int len, int *new_length)! {! ********************** SNIP *********************! while (from < end) {! c = *from++;! ! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! } while ループで文字列終端まで from を 1 文字ずつ走査 スペースを + に置換して to に格納 それ以外のエンコード対象の文字は パーセントエンコードして to に格納 エンコードしない文字はそのまま to に格納
  • 33. PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)! {! register int x, y;! unsigned char *str;! ! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! } rawurlencode() の実装 (EBCDIC モード時の処理は省略)
  • 34. PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)! {! register int x, y;! unsigned char *str;! ! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! } rawurlencode() の実装 (EBCDIC モード時の処理は省略) for ループで文字列終端まで 1 文字 ずつ走査
  • 35. PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)! {! register int x, y;! unsigned char *str;! ! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! } rawurlencode() の実装 (EBCDIC モード時の処理は省略) for ループで文字列終端まで 1 文字 ずつ走査 とりあえず str に文字を格納
  • 36. PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)! {! register int x, y;! unsigned char *str;! ! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! } rawurlencode() の実装 (EBCDIC モード時の処理は省略) for ループで文字列終端まで 1 文字 ずつ走査 エンコード対象の文字ならパーセントエンコード とりあえず str に文字を格納
  • 39. なぜ空白を + に置き換えるか 技術/HTTP/URLエンコードで 0x20(スペース) を "+" にすべきか "%20" にすべきか - Glamenv-Septzen.net
 http://www.glamenv-septzen.net/view/1170
 ※PHP に関する記述 (rawurlencode() が用意された経緯など) は若干事実と異なる部分がある。本スライドで詳述
  • 40. なぜ空白を + に置き換えるか • application/x-www-form-urlencoded のため • W3C の規格 (たとえば HTML 5) などに含まれる (単独の 規格は存在しない) • form が submit された場合のレスポンスボディのエンコー ド方式 • 空白を + に置き換えるほかはだいたいパーセントエンコード
  • 41. 他の言語の状況 • Python 2 (Python 3 では urllib.parse) • RFC 3986 の URL エンコード: urllib.quote() • application/x-www-form-urlencoded: urllib.quote_plus() • Ruby • RFC 3986 の URL エンコード: ERB::Util.u(), URI.encode() • application/x-www-form-urlencoded: URI.encode_www_form(), CGI.escape() • ただし URI.encode() は obsolete で、 ERB::Util.u() とかが代替となっている模 様
  • 42. urlencode() の歴史 • PHP/FI 2.0 から存在 • この当時から空白 (U+0020) を + (U+003B) に置き 換える実装になっていた char *php_urlencode(char *s) {! ********************** SNIP *********************! for(x=0,y=0; s[x]; x++,y++) {! str[y] = s[x];! if(str[y]==' ') {! str[y]='+';
  • 43. rawurlencode() の歴史 • PHP 3.0b3 から存在 (当時は RFC 1738 ベース) • まーた PHP 3.0 か! • RFC 3986 は 2005 年 1 月 • PHP 3.0 は 1999 年 (PHP 3.0b3 は 1998 年) • PHP 5.0 のタイミングで RFC 3986 ベースに変更
  • 44. rawurlencode() 誕生秘話 (序章) • 1997/06/16 (PHP/FI 2.0b12) • UrlEncode() がスペースを + に置換するようになる • 1997/11/12 (PHP/FI 2.0) • UrlEncode() が / をエンコードしないようになる (後に撤 回) • URL 文字列全体のエンコードを意図した 議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2
  • 45. rawurlencode() 誕生秘話 (事件篇) • 1998/01/15 頃 (PHP 3.0b3 開発中) • Jaakko Hyvätti が urlencode() で & をエンコードしないように変 更? (意図の説明を user ML にポストしたようだが入手できず) • PHP/FI 2.0 での変更の意図に合わせたもの • おそらくここで rawurlencode() と formencode() (おそらくリリー ス前に削除) が入ったと思われる ([PHP-DEV] ML で my rawurlencode() などと説明しているので) • PHP 3.0b3-dev の urlencode() が壊れたと報告がくる 議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2
  • 46. rawurlencode() 誕生秘話 (解決篇) • 1998/01/16 • PHP 2.0 の変更が不適切ということになり、スペースを + に置換する版まで戻される • ちなみに Jaakko は「rawurl*code() っていい名前ない?�urlpath*code() とか?」 とも言ってるが Rasmus 華麗にこれをスルー • スペースを + にする件も戻した方がいいのでは、という Jaakko の提案に Rasmus は反対 • 「スペースが + になっていれば urldecode() なしで POST data が使える」、 「URL 中の + は自動的にスペースにデコードされる」(= つまり + なら URL と POST data どっちもいける) • 既存のコードが壊れる 議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2
  • 47. urlencode() と rawurlencode() についてのまとめ • URL 中の文字列のエンコードをおこなう際は、 rawurlencode() を使ったほうがよい • urlencode() を使うべき場面は滅多にない • 名前的に urlencode() の方が正しそうなので多用されがち だが…… • 自力で POST データのエンコードをしたい場合くらい • そもそも RFC�3986 にも追従していない
  • 48. 問題のあった事例 • Bug(バグ) #3383: mail_to 関数を用いるときに空白が + に変換されてしまう - OpenPNE 3
 https://redmine.openpne.jp/issues/3383 • ここで気がついた (symfony の link_to() は urlencode() を使っている) • 空白を意図して渡していても + をスペースに展開しない メーラがあったと思われる
  • 50. PHP における浮動小数点数 • 精度は環境依存だが、通常 IEEE 754 の double (倍精度 浮動小数点数) • PHP では float 型ということで統一されている • 型キャストの際に (double) や (real) しても float にな る
  • 51. 浮動小数点数の (?) 歴史的な理由 • 「double は float と同じものだと考えてください。 2 種類 の名前が存在するのは、歴史的な理由によるものです」
  • 52. float / double 型の歴史 • PHP/FI 2.0 (1997/11/12) : double • PHP 3.0 (1998/06/06) : double (float, real でもキャスト できるように) • PHP 4.1.0 (2001/12/10): float……? • 2c275bf793f70ad2a38bbf4a0f7ad12fecaca095, 03f7406711d3706af0f237e1ea03974616dd2139 など
  • 53. なんで double -> float に なったか • 不明…… • ML では議論されてない? • 突如として float 派が出現したように見える [要出典] • 無理に double を float に置換する必要があったのかどう か疑問
  • 54. float 派の闘いの記録 • Hartmut Holzgraefe • double -> float への置換をおこなった最初の人物 • 多くの double -> float の置換に貢献 • Jeroen van Wolffelaar • ドキュメントに存在するほとんどの double を float に置換した • Gabor Hojtsy
  • 55. float 派の登場 • Hartmut Holzgraefe による 2001/09/21 のコミット (2c275bf7) で、 floatval(), is_float() のエイリアスとし て doubleval(), is_double() を使うように変更 (それまで は逆) • さらに (03f74067) で関数定義部分のコメント (返り値や 引数型などが書かれている) の double を float に置換
  • 58. float 派の反撃 php has no ‘double’, only ’float’ しかし止まらない double の追加
  • 59. そして 1 年が経ったある日 “php has no ‘double’” とはなんだったのか
  • 60. ドキュメントの置換も忘れない • r53773 (2001/08/07) by Jeroen van Wolffelaar • r54456 (2001/08/12) by Jeroen van Wolffelaar • r54918 (2001/08/14) by Jeroen van Wolffelaar • r57972 (2001/09/21) by Hartmut Holzgraefe • r57997 (2001/09/21) by Jeroen van Wolffelaar • r57999 (2001/09/21) by Jeroen van Wolffelaar
  • 62. 未だ残る double の痕跡 • 「歴史的な理由により、 float の場合には “double” が返 されます。 “float” とはなりません」
  • 64. Phar アーカイブのマニフェスト 情報における歴史的な理由 • 「Phar マニフェストは高度に最適化された書式で (略) 1 バイトをこえる大きさの値はリトルエンディアン形式のバイト 順で保存されます。ただし API バージョンだけは例外です。 これは 3 ニブルのデータですが、歴史的な理由によりビッ グエンディアン形式のバイト順で保存されます」
  • 66. Phar アーカイブの構造 スタブ マニフェスト コンテンツ シグネチャ (optional) Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了
  • 67. Phar アーカイブの構造 スタブ マニフェスト コンテンツ シグネチャ (optional) Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了 バージョン情報などのメタ情報
  • 68. Phar アーカイブの構造 スタブ マニフェスト コンテンツ シグネチャ (optional) Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了 バージョン情報などのメタ情報 アーカイブの内容
  • 69. Phar アーカイブの構造 スタブ マニフェスト コンテンツ シグネチャ (optional) Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了 バージョン情報などのメタ情報 アーカイブの内容 パッケージ検証用のシグネチャ。 Phar 形式のみ
  • 70. Phar アーカイブのマニフェスト マニフェストの長さ (Little Endian) 格納するファイルの数 (Little Endian) ビットマップフラグ (Little Endian) API バージョン (Big Endian) エイリアスの長さ (Little Endian) エイリアス (※任意桁) … メタデータの長さ (Little Endian) メタデータ (※任意桁) … ファイルのリスト (※任意桁) …
  • 71. Phar アーカイブのマニフェスト マニフェストの長さ (Little Endian) 格納するファイルの数 (Little Endian) ビットマップフラグ (Little Endian) API バージョン (Big Endian) エイリアスの長さ (Little Endian) エイリアス (※任意桁) … メタデータの長さ (Little Endian) メタデータ (※任意桁) … ファイルのリスト (※任意桁) … ニブル単位でバージョンを表現
  • 72. Phar アーカイブのマニフェスト マニフェストの長さ (Little Endian) 格納するファイルの数 (Little Endian) ビットマップフラグ (Little Endian) API バージョン (Big Endian) エイリアスの長さ (Little Endian) エイリアス (※任意桁) … メタデータの長さ (Little Endian) メタデータ (※任意桁) … ファイルのリスト (※任意桁) … ニブル単位でバージョンを表現 検証用のシグネチャが含まれて いるか、圧縮されたファイルが存 在するかなどのフラグ
  • 73. Phar アーカイブのマニフェスト (composer.phar (1.0.0-alpha8) の例) 0x17F-82 : マニフェストの長さ (26489) 0x183-86 : ファイル数 (322) 0x187-88: API バージョン (1.1.0) ※最後の 4bit は未使用 0x189-8C : ビットマップフラグ (0x00010000 : この Phar には検証用シグネチャが含まれる) 0x18D-90 : この Phar のエイリアスの長さ (13) 0x191-9D : エイリアス (composer.phar)
  • 74. バージョン情報のみ ビッグエンディアンである理由 • 3842b67 には元になった PHP_Archive に由来する理由とある • PHP_Archive の最新の実装もバージョン情報だけビッグエンディアンで格納している (PHP_Archive_Creator::serializeManifest()) • PHP_Archive の 2f41f8f48 ではアーカイブ作成時にビッグエンディアンで格納 しているが、展開時にはリトルエンディアンでパースしようとしている • PHP_Archive の 8931abf6 で展開時にもビッグエンディアンでパースするよう修 正された • つまり、間違えてビッグエンディアンで格納してしまったために後に引けなくなった のでは……
  • 75. ZEND ENGINE の HASHTABLE
  • 76. Zend Engine の HashTable API における歴史的な理由 • 「hash exists for historical reasons and is always ignored」
 (拙訳: 引数 hash は歴史的な理由のために存在し、常に 無視される)
  • 77. Zend Engine の HashTable API における歴史的な理由 • 時間切れで追い切れず • まあなんとなくわかる
  • 78. まとめ • 身近な機能とかを深追いしていくのは結構楽しい • PHP 3.0 時代のチェンジログと ML は本当にオススメ • たとえば「昔の PHP は + 演算子で文字列結合できたんだよー」と か無駄知識を披露してドヤ顔できる • 5 個がっつり深追いしていくだけでも結構時間が埋まるので助かった • Phar とか Zend Engine 周りの歴史的な理由が出てきたおかげで割 と闇 PHP っぽくなった気がする