読者です 読者をやめる 読者になる 読者になる

k-holyのPHPとか諸々メモ

Webで働くk-holyがPHP(スクリプト言語)とか諸々のことをメモしていきます。ソースコードはだいたいWindowsで動かしてます。

キーでarray_filter()する方法とIMAGETYPE定数から得られる情報

PHP

イテレータよりも配列大好きなPHPerは array_filter() を愛用していることと思いますが(?)、PHPには配列のキーでフィルタかける関数がないのが残念なところです。

何か代替案はないかと思って調べたところ、array_intersect_ukey() を使って実現できました。

参考記事
コールバック関数でキーをフィルタリングする - Sarabande.jp

array_intersect_ukey() は、キーを基準にコールバック関数を用いて 他の全ての引数に存在する 第1引数(配列)の値を全て有する配列を返します。
第2引数までが必須で後は可変、最後の引数にキー比較用の callable を指定しますが、第1引数と第2引数に同じ配列を指定し、コールバック関数では2つのキーの比較ではなく単にキーを評価して有効としたい場合に0を返せば、キーでフィルタかけるのと同じ結果が得られるという寸法です。

やりたかったこと

IMAGETYPE_*** 定数を元に拡張子やMIMEタイプを返す関数があるので、それらの関数が返す値や環境ごとに異なる画像への対応状況を調査するために、頭に IMAGETYPE_ と付く定数の値のみ抽出したかったのです。

なお、get_defined_constants(true) でカテゴリ名をキーにグルーピングされた定数のリストを取得できますが、IMAGETYPE定数は "gd" カテゴリではなく "standard" カテゴリに含まれています。
この辺の情報ってマニュアルから見つけられなかったんですが、ないんでしょうか?
定義済み定数にもカテゴリ名は記載されてないし。

サンプルコード

ともあれ、コードはこんな感じに。

ややこしいんですが、画像タイプに関する定数は GDで使われる IMG_** と前述の IMAGETYPE_** の2種類あって、GDでサポートされている画像形式をビット値で返す imagetypes() では前者を使う仕様になってます。
この関数を使ってIMAGETYPE定数から対応可否を返すクロージャ $supportedImageType を array_walk() の第3引数に渡してます。
そうすると array_walk() で呼ばれるコールバックの第1引数が配列の値(IMAGETYPE定数値)、第2引数が配列のキー(IMAGETYPE定数名)、第3引数がコールバック $supportedImageType になるので、それを実行して対象のIMAGETYPEに対応しているかどうかを取得しています。
あとは標準関数の image_type_to_mime_type()MIMEタイプを、image_type_to_extension() で拡張子を取得しています。

出力部分はこちらです。

書いてて何か既視感を覚えたので、自分のGistから検索してみたら、1年近く前に同じことをやっていたという…。orz
せっかくなので、その際のコードも前述の出力に合わせておきました。

array_fill_keys() で値がNULLの配列を作っておいて、array_walk() でオブジェクトに書き換えるという超強引なことやってます。
まあ、分かりやすさではどっちもどっちという感じですが…。

こちらは変更前のコードです。
https://gist.github.com/1437431/f532d2e51d1b74bf0cc5debf018f00243b7239b3

妙に短いなと思ったら、よく見るとIMG定数とIMAGETYPE定数を混同していますね…危ない危ない。

余談:XBMフォーマットについて

GD関数はXBMフォーマットにも対応しているようですが(imagecreatefromxbm(), imagexbm())、なぜかIMG定数では "IMG_XPM" という定数になってます。
これに対してIMAGETYPE定数では "IMAGETYPE_XBM" という定数があって、多分PHP的には同じフォーマットを指していると思うんですが、業務では対応することないし、面倒なので調べていません。

適当に検索してみた限りでは、このフォーマットはX-Windowシステムで使われる、白黒の画像をピクセル単位に黒を1,白を0にして16進数で記述するテキストの画像フォーマットらしいです。
XPMの方はXBMのカラー版みたいな感じでしょうか?中身は全く別のフォーマットに思えるんですが、実際どうなんでしょうか。

試しに白黒のgif画像をxbmで出力してみたところ、どうも imagexbm() はマニュアルの記述とは異なり、第2引数が必須のようです。
第2引数を指定しないと Warningが発生し、NULLを指定するとエラーもレスポンスも返らなくなりました。詳しく追跡はしませんが、ファイル出力した方が良さそうです。

あと手元の環境ではIE, Firefox, Chromeとも表示されず、Operaのみ表示できました。
レスポンスヘッダを見たところ、Apache2.2 では .xbm の Content-Type は "image/x-xbitmap" が返されているみたいです。
(image_type_to_mime_type(IMAGETYPE_XBM) では "image/xbm" が返されるんですが…)

ちなみに、ビルトインサーバの場合は拡張子 .xbmMIMEタイプを返してくれないため、ブラウザで見ると #define 400x400_width 400 #define 400x400_height 400 static unsigned char 400x400_bits[] = { 0xFF.... } という感じでテキスト出力されます。
PHP: ビルトインウェブサーバー - Manual

XBMを扱うかどうかはおいとくとしても、条件付きGETへの対応も考えると、動的にせよ静的にせよスクリプトを通して画像を返す場合は、ちゃんとスクリプト側でヘッダを組み立てた方が良いでしょうね。

そもそもGDなんて情弱が使うものだろう、とか言われてしまいそうですが、今のところGDで事足りてるしWindows版のPHP5.4対応dllなんて無さそうだし…って思ってたら…。
Imagick for PHP 5.4 Windows Build

そのうち試してみます。