tonextone.com/note/

Last-modified: 2006-09-01 (金)

Copyright ©master_at_tonextone.com All rights reserved.

open_basedir の 怪

Posted : 2006-06-12 00:00 / Category : [開発日誌]
PHP は、mod_php での運用がデファクトスタンダードになっている。
共用のレンタルサーバでも、mod_php が使えるのが普通だろう。

で、safe_mode, open_basedir なわけである(参考)。

私がこれまで構築してきたサービスは、
専用サーバで、管理者アカウントを外部に配布しない、
いわゆる「自社サービス」がほとんどだったので、
safe_mode, open_basedir 系は実際に本気で使った経験が無かった。

で、最近構築しているサービスが、複数の仮想ホストでの運用になるので、
初めて本気で open_basedir を使ってみた。

…これが、なかなか上手くいかなかった。
ここ2ヶ月くらい、試しては上手くいかず、あきらめ切れず、また試す…
の繰り返しだったが、やっと上手くいった。

合理的な原因が見つかっていないので、様子をみている段階だが、
現段階の結論:
httpd.conf で、 open_basedir の設定をしている場合、
.htaccess で、 mbstring.* 系の設定をすると、
open_basedir が不具合を起こすようだ。
php.ini / ini_set() なら大丈夫っぽい。

以下、現象 〜 経過を早送り:
  • open_basedir の設定を httpd.conf の<VirtualHost>コンテナに書くと、
    以下のようなエラーが出る。
    PHP Fatal error:  Unknown: Cannot find serialization handler xxx in Unknown on line 0, referer: xxxxxxxxx
    
    mod_php が PHP の構文解析に失敗しているような感じ。
  • このエラーの再現率は、30% 程度。
  • zend-multibyte, Zend Optimizer を怪しむ(野生の勘)。
  • 怪しい部分について、有効 / 無効を切替えたり、
    考え得る設定の組み合わせを、ほとんど総当りで試す。
  • 解決の兆しも見えず…。
  • やけになって、デフォルトの php.ini で試す。
  • 相変わらず…(´Д⊂ モウダメポ
  • .htaccess での設定とか、ini_set() 系の設定も消してみる。
  • あ、良さそう。
  • 設定調整して様子見。« 今ここ。
なんていうか、微妙すぎ…。

俺的PHP似非フレームワーク

Posted : 2006-05-29 00:00 / Category : [開発日誌]
前のエントリで、まとめるって言ったけど、
そんな大層なものでもないし、ちゃんとまとめる自信が無くなってきたので、
とりあえず簡単に説明すると…

スクリプトを埋め込めるんだから、PHP 自体がテンプレートシステム。

メリット
テンプレートシステムを導入しなくて良い。

デメリット
PHP そのものなので、何でもできてしまうという意味で、リスクがある。

テンプレート上の HTML コードは、関数として定義する(必要であればブロックに分けて)。

例えば、テンプレート上に、ループするブロックがある場合、
そのブロックの始まりと、終わりに、関数定義の始まりと、終わりを埋め込む。
つまり、
<? function hoge_loop($_){ ?>
と、
<? } /* function hoge_loop($_) */ ?>
とで、囲む。
ブロック内で展開したい変数は、'$_' という連想配列に入れて引数として渡す。
残りのブロックも同様に関数化する。
「レンダリング」= 関数のコール。
メリット
「レンダリング」を、ブロック単位で制御できる。

デメリット
テンプレートに、<? function foo_bar($_){ ?> とか記述されていてキモい(が、もう慣れた)。
間違って消されると「そんな関数見つかりません」系のエラーが発生する。

ヴューに対してリクエストがあって、対応するコントローラが読み込まれる。

テンプレートたる PHP ファイルから、ロジックが別ファイルとして分離されて
ヴュー → コントローラ の対を成す
»「ページ・コントローラ」!

ヴューがリクエストを受けて、ヴューがコントローラを読み込むイメージ。
(フロント・コントローラの逆…)
»「リア・コントローラ」!!

特定のヴューに対応するコントローラは、
ヴューの SCRIPT_FILENAME から 1 対 1 に自動決定され、include 系の命令で読み込まれる。
そのコントローラの中で、
ブロック単位で、テンプレートの「レンダリング」(=関数のコール)が行われる。

ついでに、拡張子 html で mod_php が動作するように設定して、
テンプレートたる PHP ファイルの拡張子は html とする。
メリット
「ページ・コントローラ」の〜:
ロジックがページ単位で分割されるので、
工数を見積もる際に見通しが良く、メンテナンスも容易。

「リア・コントローラ」の〜:
mod_rewrite やら、ルーティングやら、による仮想 URL じゃなくて、
静的 HTML と同様に、URL に対応するパスに
HTML っぽいファイル(実は PHP)が実在するので分りやすい
(テンプレートを担当するデザイナにも受け入れられやすい)。

デメリット
「同一の URL に対するリクエストだけれど、
 リクエスト変数によって条件分岐してヴューを切替えたい」というような場合には、
例外的にフロント・コントローラ的なものを配置する必要がある。

モロモロの処理を auto_prepend, auto_append .

上記の、 ヴュー → コントローラ の対応付けや、
その他、お決まりの処理(セキュリティ対策、DB接続、セッション、認証など)は、
1 つのファイル(prepend.php とか)にまとめておいて、それを auto_prepend .
更に、コントローラの読み込みや、その他、後始末系の処理も、
1 つのファイル(append.php とか)にまとめておいて、それを auto_append .
メリット
テンプレートたる PHP ファイルに、include 系の命令が一切露出しないので、
テンプレートとしてスッキリするし、ちょっとだけセキュアな気もする。

デメリット
あるのかもしれないが特に感じない。

include 系を随所で使う。

フロント・コントローラでは、全ての処理が一箇所に集まるので DRY にしやすいが、
「ページ・コントローラ」では事情が違う。
代わりに、include 系の命令を多用する事で、DRY を追求する。
メリット
あるのかもしれないが特に感じない。

デメリット
ルールが無いと見通しが悪くなる。

という感じなんだけど…

PHP でしかあり得ない仕組みなので、他の言語から見ると気持ち悪いだろうけれど、
デザイナとの分業のし易さを追求した結果の産物であって、
実際、その意味では充分な効果が得られたと思う。

幸か不幸か、私がまともに使えるのは PHP だけなので、
今でも、特に違和感も不便も感じず、普通に使っているけれど、
そろそろ、その違和感とか不便さを理解しといたほうが良い気がする(汗笑)。

それには、PHP 以外を使ってみる必要があるだろう、
というわけで、 Perl を改めて勉強しようと思った次第。

トラックバック

(4)

ツッコミ

1: master (06/03 14:28)
俺がフレームワークに求めるのは、規約であって制約ではない。
と、ふと思った。
[ このエントリへはツッコミ出来ません ]

PHP の強み

Posted : 2006-05-28 00:00 / Category : [開発日誌]
オープンソーステクノロジー勉強会 第3回」に参加した。
今回のテーマはウェブアプリケーションフレームワーク。
高橋さんが RoR 、藤本さんが Ethna の紹介をするという、大変に豪華な勉強会だった。

高橋さんのお話で興味深かった点をメモ:

RoR: 実行環境の現状。

Apache + mod_ruby :
ruby が富豪的なので、
実際は、Apache + mod_ruby をアプリ専用にして、
フロントにもう一個ウェブサーバ立てるのが普通。
→ 面倒。
じゃあ、WEBrick とか:
フロントに Apache 立てておいて、
アプリ専用のウェブサーバは WEBrick で。
$ apachectl graceful;
的な仕組みが無い。
Apache + FastCGI :
不安定?
Lighttpd + FastCGI :
結構、使われている。でも、Apache ほど多機能ではない。

RoR: 日本語化の現状。

ActiveHeart :
シンプルなので汎用性がある。
スペジェネ :
情熱的なので、ハマる場合と、ハマらない場合がある。
gettext :
本格的だが敷居が高い。

RoR: 文字コードの現状。

デフォルトの文字コード指定 :
$KCODE = 'u'; # s,e,n
フィルタで変換 :
before/after filter に、NKF, iconv フィルタとかを挿せる。

で、PHPはどうなんだ。

PHP: Apache の mod_* だけど…

mod_perl, mod_ruby
Apache を LL で拡張するためのモジュール。
→ 玄人向き。
mod_php
Apache で LL を処理するためのモジュール。
→ それ以外できない。潔い。安全。

PHP: 広く普及している。

普及率が高くて実行環境も mod_php が標準的。
共用レンタルサーバとかでも普通に提供されている。
したがって、既存のシステムの改修などにも利用し易い。

<所感>

共用レンタルサーバとかでも mod_php が採用されているのは、
mod_perl, mod_ruby と違って「必要最低限の事しかできない」からだと思う。
とは言え、mod_* であるからには、Apache の権限で実行されるので、
mod_* に関わる全てのファイルのパーミションは、
---赤の他人のファイルであろうとも---
Apache が読めるようになっている事が「必要」であり、
重要な情報を隠蔽する事が難しい(できない?)。
にもかかわらず PHP は共用サーバにも普及してしまったので、苦肉の策として
safe_mode, open_basedir
などの設定項目が設けられている。

</所感>

PHP: フレームワークは?

フロント・コントローラなフレームワークが主流だが、既存のシステムとの共存が難しいのではないか?
PHP の強みを活かすには、「ページ・コントローラ」なフレームワークのほうが、
既存のシステムと共存しやすくて良いのでは?

<所感>

「ページ・コントローラ」というのは、ページ毎にコントローラを持つという事。
フロント・コントローラ主流の昨今において、「ページ・コントローラ」は原点回帰とも言える。
最近 PHP 界隈で、そういう話がチラホラ出ているけど、半分はネタだと思う。何となく。
実際、高橋さんの話もネタだと思う。

でも、私が 5 年ほど使い続けているフレームワーク的なモノも、
そんな「ページ・コントローラ」に該当する気がする。
ネタではなくマジで使い込んでしまっている。
なので、「ページ・コントローラ」の実装例として、後でちゃんとまとめる事にしよう。

</所感>

トラックバック

(2)

ツッコミ

1: kdmsnr (06/01 17:19)
> 実際、高橋さんの話もネタだと思う。

ネタではなく、いつも言ってます。
2: master (06/01 23:39)
> kdmsnr さん
ありがとうございます。
ネタじゃないんですね!それは心強いです。
ずっと「ページ・コントローラ」でがんばってきた自分としては、
「ページ・コントローラ」という名前がついただけでも嬉しいのですが。

capsctrl チェックしてます!
[ このエントリへはツッコミ出来ません ]

JavaScript による min-height, max-height の実装。

Posted : 2006-03-16 00:00 / Category : [開発日誌]
動的なウェブサイトなどで、画面上のボックスの内容量が予測できない場合、
CSS で overflow なんか使ったりします。ですよね?
でも、overflow なボックスのサイズが固定だと、逆にまだ何も内容が無い場合に、余白になってしまいます。
「じゃあ、 max-width, max-height を使おうよ」と言う事になるのですが、
min-width, max-width, min-height, max-height は IE で実装されてません。このやろう。

なので、JavaScript で実現する感じのモノを作りました。 »デモ
仕組みは単純なので、興味があったら、ソース読んでください。

ちょっと安全かもしれない eval() の使い方。

Posted : 2006-02-27 00:00 / Category : [開発日誌]
長らくエントリのない状態が続いた後ですが、
地味な思いつきのメモです。

eval() 使ったらスゲェ簡単なのに…とか思いながら、
その強力さゆえに、恐ろしくて使えない場合が、間々ある。
いつも奥の手として持ってるだけみたいな。

良くあるのは、
'こんにちは、{$foo}さん。ようこそ{$bar}のホメパゲへ。'
みたいな文字列の中の変数に値を代入したいというやつ。

正規表現とかでやってたら回りくどいので、
何とか eval() を活用するためにセキュリティ対策を考えてみた。

ヒアドキュメント使うのがキモ。
あと、ちゃんと意識して引用符「'」「"」を使い分けて、
1 回しか評価しないように気を付ける。
ついでに、境界識別子 '$_boundary' を予測し難くすれば、悪い事もやりにくかろう。

PHP だと、こんな感じ。
<?
function eval_vars_in_string($_string,$_vars)
{
  extract($_vars);

  $_boundary = uniqid('__');

  $_code = '$_return = <<<'.$_boundary.'
'.$_string.'
'.$_boundary.';
';

  eval($_code);

  return $_return;
}

$_string = 'こんにちは、{$foo}さん。ようこそ{$bar}のホメパゲへ。';

$_out = eval_vars_in_string($_string,$_POST);

?>

という思い付きでした。[サンプル]

コメント歓迎。

ツッコミ

1: itoh (04/05 15:20)
これ、どうやってsystemコード書きます?
2: master (04/06 13:39)
この関数の使命は変数展開で、
system 関数の評価/実行までは行わないというのがキモです。

system 関数を動的に生成して実行したい場合は、
まず、system 関数のコードを動的に生成して、
もう一回 eval(); すれば、実行されるかと。

ただし、リクエスト変数の無害化は、別途必要です。

<?
$_vars = array('path' => '.');
$_string = ' system(\'ls {$path}\'); ';

$_out = eval_vars_in_string($_string, $_vars);
?>
<pre>
<?
var_dump($_out);
eval($_out);
?>
</pre>
[ このエントリへはツッコミ出来ません ]