pharでWebアプリを作ってみた

[pharを使ってみる](http://qiita.com/rana_kualu/items/d868604a1f54c2f93a7c) / [pharアーカイブを作成](http://qiita.com/rana_kualu/items/4b2ef7bfff83939d7ef5) / [pharでWebアプリを作ってみた](http://qiita.com/rana_kualu/items/e437fff6f558c053cc41)


[前回](http://qiita.com/rana_kualu/items/4b2ef7bfff83939d7ef5)はpharアーカイブをライブラリとして使用しましたが、実はpharアーカイブだけで完全な動作をするPHPプログラムを作成可能です。
この利用法、[Phar::webPhar()](http://php.net/manual/ja/phar.webphar.php)あたりをよく読めば書いてあるのですが、物凄く便利っぽい機能にもかかわらず何故か何処にもこれを使ってみたという人が見あたらない不思議。

まあとりあえずでっちあげてみたのが[こちら](http://file.yuubiseiharukana.blog.shinobi.jp/20110730-index.phar.zip)。

中身は[大昔に作った超適当なフォーム](http://yuubiseiharukana.blog.shinobi.jp/Entry/17/)なのでソースは絶対に参考にしてはいけませんが、以下の3ファイルが入っています。

input.php

```php
<?php
	//初期化
		header("Content-Type: text/html; charset=UTF-8");
		error_reporting(E_ALL ^ E_NOTICE);
		$shimei = '';
		$mail   = '';
		$sex    = '';
	
	//引数を確認
	if($_REQUEST['comp']){
		//引数があれば入力チェック
			$shimei = $_REQUEST['shimei'];
			$mail   = $_REQUEST['mail'];
			$sex    = $_REQUEST['sex'];
			$error_message = '';
			if(empty($shimei)){    $error_message.= "氏名が入力されていません<br />";}
			if(empty($mail)){      $error_message.= "メアドが入力されていません<br />";}
			if($sex!=1 && $sex!=2){$error_message.= "性別が入力されていません<br />";}
			if($error_message){
				//エラーがあれば戻る
				require_once('phar://index.phar/input.tpl');
				exit();
			}else{
				//エラーがなければ保存して終了
				file_put_contents('form.txt', $_REQUEST, FILE_APPEND);
				require_once('phar://index.phar/comp.tpl');
				exit();
			}
	}else{
		//引数が無ければ入力画面
		require_once('phar://index.phar/input.tpl');
		exit();
	}
```

input.tpl

```php
	<?php if($error_message){print('<div style="color:red;">'.$error_message.'</div>');} ?>
	<form method="POST" action="<?php print(htmlspecialchars($_SERVER['PHP_SELF'])); ?>">
	   氏名：<input type="text" name="shimei" maxlength="64" value="<?php print(htmlspecialchars($shimei)); ?>"><br />
	   メアド：<input type="text" name="mail" maxlength="64" value="<?php print(htmlspecialchars($mail)); ?>"><br />
	   性別：
	   <input type="radio" name="sex" value="1"<?php if($sex==1){print(" checked");} ?>>男　
	   <input type="radio" name="sex" value="2"<?php if($sex==2){print(" checked");} ?>>女<br />
	   <input type="submit" name="comp" value="　登録　">
	</form>
```

comp.tpl

```php
	投稿を受け付けました。<br />
	ご協力ありがとうございました
```

適当にサーバに置いてブラウザからindex.pharを呼び出すと、普通にフォームが動作します。
ファイルをひとつぽんとサーバ上に置くだけでフォームが完成という、配布などに非常に便利な機能となっています。
まあ、この例で作ったフォーム程度なら手動で1ファイルにした方が早いんですが、というかわざわざpharにする必要全くないんですが、たとえばファイルが2200個ある[Mantis](http://www.alles.or.jp/~sogabe/mantis/)がなんと今ならたった1ファイル、とかになったらずいぶん利用のハードルが下がったりするかもしれません。


ちなみにこのpharファイルの作成方法は以下のようになっています。

```php
<?php
	$phar = new Phar('index.phar', 0);
	
    $phar->addFile('input.php');
    $phar->addFile('input.tpl');
    $phar->addFile('comp.tpl');
    $phar->setStub('<?php
		 Phar::webPhar("index.phar", "input.php" );
		 __HALT_COMPILER(); ?>');
```

[Phar::webPhar()](http://www.php.net/manual/ja/phar.webphar.php)が、pharファイルを直接呼び出しで動作できるようにしてくれるフロントコントローラです。
このメソッドを呼んでおくと$_REQUESTとかの処理を適切に割り振って、pharアーカイブ内でそのまま使用できるようにしてくれます。
第二引数の'input.php'を指定すると、index.pharが呼ばれたときにアーカイブ内の'input.php'が実行されるようになります。

このPhar::webPhar()をセットしている[Phar::setStub()](http://php.net/manual/ja/phar.setstub.php)はローダスタブをpharアーカイブにセットするメソッドです。
で、そのローダスタブって何なのかというと、今回のようにpharファイルを直接呼び出した、あるいは`require_once('index.phar')`と直接pharアーカイブがインクルードされた際に自動的に実行される部分です。
`'phar://index.phar/input.tpl'`とpharアーカイブ内の一部ファイルだけを呼び出した際には実行されません。
デフォルトだと、phar未対応のPHPでpharをエミュレートする機能を追加し、その後自動的にアーカイブ内の'index.php'を実行してくれるようです。

なおpharが入っていれば、zipやtarのままPHPとして動作させるなんてこともできてしまうようです。
そこらへんは調べてないのでよくわかりません。

__HALT_COMPILER()なんて初めて使ったよ。