今日はプログラミングのお話。この Rauru Blog で使っている WordPress とゆう Blog プラットフォームについては私も3年前に使い始めてから愛憎半ばするものがあるわけですが、先週末は WordPress について「確かに WordPress には問題が多いのを否定できんのう」と思う文章をいろいろ見かけたので(主にotsuneさん経由)、言及しておこう。
まず、WordPress が コボラライゼーション の実例になりかけていることの警鐘。
僕は Ben が WordPress を使ってることを知った。というわけで、僕はダウンロードしてそのソースにざっと目を通してみたんだ。そしたらすぐに気がついたんだ。
- PHP 5 は使われていない
- 関数名のプリフィックスで同じような関数がまとめられていて、クラスに隠蔽されていない
- bound parameters が SQL 文で使われていない
- Model, View, Controller の間の区別がそれほどない
- XML の生成が print() や echo() 経由で行われていて、 PHP の XML クラスや関数を使っていない
これらの殆どが即座に警告を引き起こした。 SQL bound parameters がの欠落は SQL インジェクションへの防御が難しくなるって事だ。 MVC の欠落は XSS の可能性を増加させる。クラスを使わないって事は、 API を理解しづらくなるって事だ。 PHP 5 の可視範囲のキーワード (public, protected, private)を使わないって事は、将来におけるコードの対応を確実にするのが難しくなるってことだ。
National Vulnerability Database で WordPress のおおまかな経緯について疑惑を強めたところで、僕はこいつにはチャンスを与えないことを決めた。このソフトウェアは簡単に使えるし多分きちんと動くだろうけど、僕はセキュリティを運否天賦に委ねる気には全くなれない。そのうえ、PHP 伝道師としては三年に渡る PHP の発展を利用していないソフトウェアを自分のサイトに置くべきじゃないだろう。
しかしなぜ WordPress がコボラライズしているのか。一つ目には PHP4 のサポートを落とすわけにはいかん っつう WordPress 側の姿勢があります。WordPress は PHP4 (4.3以降) でも動かにゃならんのだそおです。Ryan Boren が去年 WordPress and PHP 5 つう記事でそれを明言してる。互換性の呪縛ぢゃよのう。落として欲しいんだがなあ…
そしてもう一つ。これも根っこが一緒っちゃあ一緒なんですが、カジュアルな開発者への訴求力
つう点があります。ここで言うカジュアルな開発者てのは、クラス/オブジェクトを扱えない開発者 ならびに セキュリティ意識の低い開発者 を足して二で割ったような意味だと思ってください。WordPress が MovableType を超える人気を得た要因には、これもでかかったと私は思ってます。つまりこういう話。
WordPressに見るオープンソースWebアプリに向いた設計とは (pot)
とりあえずタイトルに対する結論から列挙しますと、(bbPressですが)
- 言語はPHPしかありえない
- インストールに黒い画面(ターミナル)を使う必要があってはいけない
- FrontControllerを使わない。(URL見たまんまのファイルがあること)
- クラスを使わない。functions.phpとかにbb_xxxxとかいう関数を列挙する。
- テンプレート言語はPHP。theme/default/以下とかに置いて、前述のURL見たまんまファイルと同名にする。(register.phpとか)
- ディレクトリ構造はフラットに近くする
- gettextを使っておくと自然と翻訳してくれる人が現れる
作者はとにかく「サードパーティー開発者」と「ユーザー」に奉仕して、DRYに反していても誰にでもわかりやすいまま頑張ってスパゲッティにならないようにします。
より多くの「サードパーティー開発者」に気に入ってもらえるようにすることがひいてはプラグインの増加、ソフト自身の価値向上につながるんですね。
このサードパーティ開発者/ユーザと呼ばれてる人たちですが、WordPress の開発コミュニティにはだいたい以下の3種類の人がいます。ただしこの3種類は綺麗には分かれていません。境界が曖昧で、それが開発者を集めるには役に立っているんですが、同時に問題も引き起こしてると思う。
- Theme 開発者
- Plugin 開発者
- コア開発者
WordPress における Theme てのは MovableType におけるテンプレートに相当するものです。ただし、MovableType のテンプレートはほんとにテンプレートですが、WordPress の Theme は PHP 実行ファイルです。Theme ファイルが本当に PHP として実行されます。なので、悪質なコードが埋め込まれた Theme を WordPress にインストールすると、それが PHP (たいてい Apache) の権限で実行されるため、ろくでもないことになります。
しかし WordPress の Theme 作成に関するドキュメントは、そのことについて開発者の注意を喚起する書き方になってるとは言いがたい。逆に、そういう意識が無いままでも — 極端な話 PHP について知識が無くても — Theme ファイルを書けるよう 親切な 書き方になってます。PHP の関数を テンプレートタグ と呼んでるのもその一例です。例えば <?php bloginfo('name'); ?> てのは Blog 名を表示するタグとされてます。PHP のことを何も知らなくても、Theme ファイルにこの呪文のようなタグを書けば blog 名が表示されるんです。なんてわかりやすいんでしょう!
んで、これで WordPress のコード書きに慣れた人が PHP というものを理解してくると、次は plugin を書くようになるんですよ。え? そんなん危険だろって? いや、Theme でも PHP のコード書く以上何でもできちゃうんで、plugin だけが特に危険ってことは無いんぢゃよー。
WordPress の plugin は hook と呼ばれる callback な API を使います。WordPress 本体コアのコードには、いたるところに apply_filter() とか do_action() とかいった関数が埋め込まれてます。それぞれに do_action('save_post') みたいな感じでフック名が引数として埋め込まれてます。PHPの実行がこの行に差し掛かると、同じフック名で登録された callback 関数を呼ぶんです。plugin 側では起動時に add_filter() とか add_action() とか言った関数を使って、フック名と callback 先の関数名を指定して登録しときます。do_action の場合は引数無しで呼ばれるので、やりたいことをやる。do_filter の場合は引数で文字列が渡されるのでそれを書き換えて返す、要するに文字列フィルタです。文字列を書き換える方法さえ知ってれば、クラスとかオブジェクトについて何もわかってなくても大丈夫。preg_replace() 使えるような開発者は御の字ぢゃ。たいていの plugin は単に受け取った文字列の前か後に何ぞ連結して返してるだけだぞ。
plugin 側が WordPress 本体コアの情報を参照しなきゃいかん場合、グローバル変数およびグローバル関数で情報を取ってきます。グローバル関数の方は、先に紹介した Theme 用のタグとよく似ているため(例えばblog名をprintするのはbloginfo('name')で、変数に代入するのはget_bloginfo('name'))、Theme 作成に慣れた人だとわかりやすい仕組みなのだな。クラスやオブジェクトについて何もわかってなくても大丈夫。
つうわけで、あれだ。この WordPress の plugin コードに、変数や関数の隠蔽によるメンテナンス性向上は決してない! と思っていただこうッ! いやすまん嘘だ。わかってる開発者はせめて自分のコードだけでもそれなりにしようとして、自分の plugin の中だけクラス分けしてコード書いてはいるよ。この辺の恨みつらみについては コードが汚い と文句ぶー垂れたことがある。
DBのクエリで bound parameter 使わず mysql_query() に SQL 文をパラメタ込みの文字列として直に流し込んでるのも、実はこの plugin API のためなんすよ。SQL文を filter フックで plugin が書き換えられるようになってるんです。where 句の検索条件を plugin でいくらでも付け加えられて、それもフィルタでの文字列連結だけで簡単にできる。めちゃくちゃ面白い plugin を簡単に書けるひみつもそこにあるのだった。それは当然、GET引数をそのまま文字列として SQL に入れ込むのもアリ。その場合 GET引数を サニタイズ する責任は plugin 側にあります。
なので WordPress では、plugin のせいで SQL Injection 起こすっつう例が過去けっこーありました。今後もあるだろうなあ…
コア開発者ともなるとさすがにそれなりなんですが、上記のような Theme / Plugin 開発者にやさしい姿勢は維持しないといかんので、今のような状況になっちょるわけですよ。何とかして欲しいとは私も思う。
コア開発チームは、このカジュアル開発者にやさしい姿勢は維持しつつ、いかにも穴が開きそうなところはなんとか手を打つっつう、かなーり難しいバランス取りを頑張ってるようです。まあ、応援するしかない。


July 16th, 2008 at 3:56
いつも拝見しています。WordPressは誰でもpluginやthemeで理想を追い求められるところが魅力的です。
セキュリティ面で自己責任になる部分にはやはり少々不安がありますが。
ところで、cococでrssを取得して見ているのですが、Rauru Blogさんの
http://wordpress.rauru-block.org/index.php/feed
のソースには特に変わったところはないようだしFirefoxで見てもなんともないのに、
( ! ) Warning: parse_url(http:///) [function.parse-url]: Unable to parse URL in /usr/local/www/rauru-block/wordpress/wp-content/plugins/searchword-highlight/searchword-highlight.php on line 716
というのとcall stackの15行の表が出てくるんです。feed.xmlを生成するときに何か呼び出しているのでしょうか。
他のWordPressブログでは同様のことが起きたことがなく、謎に思っています。
July 23rd, 2008 at 1:49
[...] WordPress が 問題ありまくりなコード にも関わらず大繁栄してるのも、導入し易い Theme や Plugin [...]
July 24th, 2008 at 3:52
すんません調査が遅れてますが、どうも cococ がアクセスするときに Referrer につけてくる文字列が PHP として予想外の形になってて、うちで使ってる Searchword Highlight つう plugin がその Referrer をデコードしようとしたときに warning 吐いてるらしい、つうところまでわかりました。
UA が cococ のときだけ Referrer 見ないようにすれば勝ちかもとは思うんですが、もう少し調べてみます。すんません。
July 24th, 2008 at 12:53
お返事ありがとうございました。cococを1.05a→1.05bにしたからか、今日はwarningが出ませんでした。
(前のコメントでwarningの内容がもし問題でしたら、このコメントも含めて、消していただいてかまいません)
でもなぜか新しい2つの記事の日付が1999年11月30日 火曜日 9:00に…(Firefox 3.01のライブブックマークでも)
うちでは、2.6にするだいぶ前ですが、公開済み記事を非公開に戻したのにfeedには出てしまうことがありました。素人がさわるのも怖いので記事を消してしまいましたが。
July 30th, 2008 at 21:42
[...] Rauru Blog » Blog Archive » WordPress のコードとしての問題 [...]
January 15th, 2009 at 16:23
[...] のクエリを書き換えることまでできる。これが セキュリティホールの温床 [...]