>path); fclose($conn); fwrite($conn. "HTTP/I.1 404 N0tFound\r\n"); } else { fw 「 ite($conn, $content); fwrite($conn, "\r\n"); fw 「 ite($conn, "Content-Type: text/html\r\n"); と、 png を返せるようになる 〃 HTML 固定にするよ。拡張子とかで判別して img/png とかにする fwrite($conn. "Content-Length:" . strlen($content) . "\ 「 \n"); fwrite($conn. "HTTP/I.1 200 OK\ 「 \n"); if ($content) { $content = file_get_contents($path); if ($ 「 equest → method = = ・ GET' & & is—file($path)) { 〃 GET で来ていて、ファイルが有ったら読む 2 0 ン explode( ・・ , $ 「 equestCommand); list ($ 「 equest → meth0d. $ 「 equest → path. $ 「 equest → ve 「 sion) = 〃スペース区切りでメソッド [GETIPOSTIDELETEIPUT] 、パス、パージョ $requestCommand = t 「 im(fgets($conn)); / / 1 行だけ読む、 1 行目はリクエスト内容そのもの $request = new\stdClass(); function buildRequest($conn) { fclose($socket);
「え ? bot ってプログラムでしょ ? プログラムが猫耳ショタ ? えっ ? どういう メカニズム ? 」 説明を受けたら、より一層混乱をしていると部屋の隅に、派手で悪趣味な格 好をした猫耳が座って芋焼酎を飲んでいた。 「いちいち、うるせえなー。 bot が猫耳ショタになるくらい、よく有ることだろ。 そんなことイチイチ気にしてるんじゃねえよ」「え ? 二人目、プログラムって 猫耳ショタになるものなの ? えっ ? どういうメカニズム ? 」 「そっちは、おだいった。そっちは元々はモバファクがやっていた wassr って いうサービスで、大喜利のお題を出すための bot だったんだけど。今は止まっ ているし、このパソコン借りて呼び出しておいたにや。よろしくにや。ところ で、昨日の Web サーバーの続きなんだけど。 CGI が動くようにしてみたにや」 $ 「 equest = buildRequest($conn); $buffers = while ($conn = stream socket_accept($socket)) { } else { ech0 "$errstr ( $ e 「「 no ) く b 「 / > \ n " ・ if (!$socket) { $er 「 str); $socket = st 「 eam_socket se 「 ve 「 ( " tcp : / / 0.0.0.0 : 8080 " く ?php php $content = null; $path = >path); 引 R 2 5 if (p 「 eg-match( ・ #\. php# ・ . $path)) { if ($request → method = = ・ GET ・ & & is_file($path)) { putenv( ・ QUERY_STRING=• . $que 「 Y[1ル 〃ファイル名の " ? " よりあとがクエリストリングだよ $ 「 equest-
$descripto 「 spec = array( array("pipe", "w"). / / stdout a 「「 ay("file". "/tmp/e 「「 or-output. txt" $pipes = a 「「 ay(); / / サブプロセスを立ち上ける $child = p 「 oc_open( ・ php ・ . $path. $descripto 「 spec. $pipes); 2 6 fclose($conn); fwrite($conn, "HTTP/I.1 404 N0tFound\r\n"); }else { fwrite($conn. $content); fwrite($conn, "\r\n"); fw 「 ite($conn, "Content-Type: text/html\ 「 \n"); 〃 HTML 固定にするよ fw 「 ite($conn. "Content-Length: ・ . strlen($content) . fw 「 ite($conn, "HTTP/I . 1 200 OK\ 「 \n"); if ($content) { $content = file_get_contents($path); } else { putenvCQUERY_STRlNG='); p 「 oc—close($child); fclose($pipes[l]); $content = st 「 eam_get_contents($pipes[l]); 〃レスポンスを受け取る fclose($pipes[0]); fw 「 ite($pipes[0], $ 「 equest → body); 〃リクエストボディを書き込む
fclose($socket); function buildRequest($conn) { $request = new\stdClass(); $requestCommand = t 「 im(fgets($conn)); list ($request → method, $ 「 equest → path. $ 「 equest → ve 「 sion) = explode(). $ 「 equestCommand); while (($char = fgetc($conn)) ! = = false) { $line . = $cha 「 ; fo 「 each (explode("\n". $line) as $heade 「 ) { $label = strtouppe 「 (strt 「 ($tmp[l]. ・ $ 「 equest → $label = t 「 im($tmp[2]); if (isset($ 「 equest → CONTENT_LENGTH)) { $ 「 equest → body = f 「 ead($conn, intval($ 「 equst- >CONTENT_LENGTH)); b 「 eak; 「 etu 「 n $ 「 equest; 「これ、パイプの部分が良く分からないけど、なんとなく拡張子が " php " なら プログラムを起動するっていうところが、主な変更点だよね ? 」 「その通りだにや。パイプについては、 Linux の仕組の基本だから、そのうち こでは「プログラムとプログラムの間を通信する仕組」 説明するにや。一旦、 2 7
「で、これを simple. php として保存して、それじゃ、これを "php simple. php" で起動してプラウザで " http : 〃 192.168.33.10 : 8080 / " にアクセスしてみるにや。 もし、ちゃんと動かないようなら、 " php-lsimp . php " とするとタイプミス とかは教えてくれるにや」 「おお、プラウザに " にやーん " って出た。ん、これ、世界中がアクセスでき る場所に置いたら、世界中に " にやーん " を返せるってことか ? 」 「そうにや」 「 fwrite って、アレだよね ? print みたいなもので、ファイルに書き込むんだっ け ? でも、こで返す先って通信相手のプラウザじゃないのか ? 」 「そうにや。 UN Ⅸの世界ではなんでもファイルとして見做そうとしている にや。つまり、ソケット ( 通信 ) もファイルにや」 「ふーん、分かるような分からないような。あれ ? このプログラム、リクエス トヘッダとして送ってきてるはずの、 GET とか POST とか一切出てこないぞ ? その辺は読まないのか ? 」 「良いところ気付いたにや。それじゃ、 GET の時だけファイルを返せるように $ 「 equest = buildRequest($conn); 〃リクエストの内容を解析する $buffe 「 s = while ($conn = stream_socket accept($socket)) { 〃リクエスト来るまで待ち } else { echo "$errstr ( $ e 「「 no ) く b 「 / > \ n " if (!$socket) { $socket = stream_socket_se 「 ve 「 ("tcp://0.0.0.0:8080" 〃サーパー待ち受けでソケットオープン く ?php php してみるかにや ? 」 $content= null; $path = 引 R $ 「 equest-
0N7 凹 D 5 # CGI 「そういえば、 Web サーバー作っている時に拡張子が php だったら PHP を起動するのを作る時に、 CGI がどうのって言っていたけど、ど ういう意味なの ? 」 「 CGI は Common Gateway lnterface の略にや。あそこではややこしい ことしたくなかったから拡張子 php の時に、 PHP を決め打ちで起動し ていたけど、本来は CGI という Web サーバーから外部のプログラムに データを渡しながら起動するための規格があるにや。って言っても環境 変数と標準入力を使ってデータを渡して、標準出力をそのままクライア ントへ返してやることが決まってるだけにや。たとえばにや」 # !/bin/sh echo "HTTP/I.1 200 OK\r\n" ech0 "Content-Length:2\r\n" echo "Content-Type: text/html\ 「 \n" echo "\r\n" echo "OK" 「こういうシェルスクリプトを " index. cgi " という名前で置いて、パー ションを chmod で 755 にしておくにや。」 「ふむふむ」 「そうしたら試しに . /index. cgi とシェルに打つにや。」 「うん、想像通りリクエストヘッダとリクエストボディが出たね。 この このプログラムで実行してね " って意味 1 行目の # ! から始まるのが、 だったよね ? 」 「そうにや、具体的にはソースコードの 1 7 行目の拡張子で制限してい るところを直して、 25 行目の php を直接起動しているところを $path で動くようにすれば良いにや。これでサーバーにアクセスすると OK っ て出るにや。まあ、要するに本当は言語とかどうでも良くて、シェルで 実行出来るものなら、シェルで実行した結果をそのままクライアントへ 返せるということにや。詳しいことは RFC3875 を読むにや」 ツ 3 3