コマンド・ライン PHP? もちろん可能です!

汎用スクリプトと PHP デバッグ用のコマンド・ライン・インターフェースに PHP を使う

コマンド・ラインから PHP コードをデバッグする方法を学び、PHP そのものに対するシェル・スクリプト言語としての PHP の強みを検証しましょう。

Roger McCoy (rogermccoy@gmail.com), IT Specialist, Freelance

Roger McCoy は開発者として、C や Java、JavaScript、Perl、PHP、Visual Basic など、多くのプログラミング言語を扱ってきました。彼は PHP アプリケーションの開発に 5 年の経験がありますが、おそらく彼は、コールセンター業界の技術者としての仕事で最も知られているかもしれません。



2007年 3月 13日

コマンド・ライン・インターフェース PHP の利点

私はこれまで長年の間、エンジニアとは何かに関して、風変わりな定義をしてきました。私の意見では、エンジニアというのは、あるツールを本来の目的以外の用途に使う人です。そうした使い方は必ずしも望ましいとは限りませんが、よく考えてみると、実は発明や、そしてもちろん大部分の革新は、あるものを、それ以前には必ずしも想定されていなかった方法で使うことから生まれてきているのです。

そこで、私の古くからの友人であり、Web ページ作成のための信頼できるツールである PHP を、コマンド・ライン・ツールとして使うという考えが頭に浮かんだときの私の驚きを想像してみてください。このようなことをするのは私が初めてではないかもしれませんが、この考え方は私にとっては非常に新鮮でした。

もちろん、単にコマンド・ラインに PHP を使えるからといって、そうした方が良いとは限りません。しかし、そのように PHP を試し始めた途端、いくつか嬉しい発見をすることになるのです。まず何よりも、既存のスクリプトのデバッグが、これまでとは比較にならないほど、とても簡単になります。また、主に出力から構成され、ほとんどロジックを持たないプログラムは、PHP では信じられないほど単純です。その他にも、PHP に関する全知識を活用すれば、これまで想像もしなかった作業を PHP で実現することができます。実際、どのようなプログラミング・プロジェクトであれ、PHP をスイス・アーミー・ナイフのように使って悪い理由はないのです。

素晴らしいと思いませんか。では早速、コマンド・ラインで PHP を使うと何が実現できるかを見ることにしましょう。


インストール

インストールといっても、具体的に何かをインストールする必要もないと言えるほどに簡単です。まず、コマンド・ラインで単純な PHP スクリプトを試すことから始めます。既存の PHP スクリプトを使うこともでき、あるいは下記のコードを試すこともできます。これは Linux® での例ですが、他のシステムでも原理は同じです。

まず第 1 に、PHP 実行可能ファイルの場所を確認します (大部分の Linux システムでは、まず確実に /usr/bin/php です)。よくわからない場合には、コマンド・ラインで which php と入力し、その結果を調べます。

第 2 に、下記のコードを入力し、PHP 実行可能ファイルへの実際のパスで /usr/bin/php を置き換えます。

#!/usr/bin/php -qHello world

ファイルを保存し、必ずそのファイルに実行可能パーミッションを設定します。大部分のシステムでは、そのためには chmod +x hello-world のようにします。次に、この PHP ファイルを実行し ( ./hello-world を実行するか、場合によっては php hello-world を実行します)、そのファイルが実行できるかどうかを調べます。もし実行できれば、その PHP インストールにはデフォルトでコマンド・ライン機能が含まれています。

もしコードが適切に実行できなかった場合には、ちょっと面倒です。原因としては、いくつか考えられます。もし PHP 関連のエラー (「プログラムが見つかりません (program not found)」といったようなこと以外のエラー) が出たとしたら、問題はコード中の入力ミスです。もし PHP 実行可能ファイルが見つからないのであれば、適切なパスを使ったかどうかを確認します。もし PHP という名前の実行可能ファイルがないのであれば、そういうファイルを入手する必要があります。

PHP 実行可能ファイルを入手するための手順はシステムによって異なるかもしれませんが、必要なサポートを得るのはそれほど難しくないはずです。まず、使用しているオペレーティング・システムあるいはディストリビューションのドキュメンテーションを調べることから始めてください。

当然ですが、この時点でシステムに PHP がインストールされていないのであれば、まず PHP をインストールし、それから再度、上記のコードを試します。多くのシステムでは、PHP をインストールするだけで終わりのはずです。さらに何か他のことをする必要があるとしても、適当なパッケージ管理ツール (apt-get あるいは yum など) を使って PHP CLI パッケージ (名前は少し異なるかもしれません) を入手するだけで、簡単にこの問題を修正できるかもしれません。

もし PHP パッケージ管理ツールの中にコマンド・ラインが見つからない場合には、最悪のシナリオとして、--enable-cli フラグを付けて PHP を再コンパイルします。実際、再コンパイルすると、わずかながらシステムがさらに最適化されるため、これは悪い考えではありません。いずれにせよ、始めるための準備を整えるのは難しくないはずです。

ここまで来れば、HelloWorld スクリプトは既に実行しており、その出力は皆さんが想像したとおりになっているはずです。ここではスクリプトの動作の詳細は解説しませんが、その大部分はシェル・スクリプトや PHP を扱う人にはおなじみのはずです。この最初のスクリプトは問題なく実行しているので (そうあって欲しいものです)、本物の CLI (command-line interface) アプリケーションから少し脇道にそれ、なぜコマンド・ラインの PHP が PHP プログラマーにとって素晴らしいのか、その大きな理由の 1 つ、デバッグについて調べることにします。


PHP によるデバッグ

これは私だけかもしれませんが、CLI プログラムのデバッグが、特に HTML に埋め込まれたスクリプト (Microsoft® の ASP (Active Server Pages) や PHP など) を処理する際には、ほとんど悪夢と紙一重に思えることがよくあります。特定のエラー・メッセージが正確に何を意味するのか判断できないことが多く、ユーザー入力は再現しにくく、そしてどれを見ても、髪の毛をかきむしりたい気持ちにさせられるのです。

残念なことに、それらの大部分はコマンド・ラインを使っても解消されませんが、ある程度賢いプログラマーであれば、その解決に CLI が役立つことがわかるはずです (例えばファイルから、あるいは別のプログラムからパイプを使って入力を読み取る、など)。しかしそれよりも、CLI によって、あることが非常に容易になるのです。つまり CLI を使うことで、エラー・メッセージを容易に見つけることができ、何よりもエラー・メッセージを読むことができるのです

コマンド・ラインを使ったデバッグの価値の高さを見るために、ものすごくひどい PHP ファイルの例から始めることにします (下記)。

#!/usr/bin/php -q
Don<'t>code<?php while drunk(); ?<

コードを見れば、このスクリプトの中にいくつかの間違いがあることはかなり明白です。しかしこのコードはむしろ、Web ブラウザーのデバッグ・メッセージがほとんど役に立たないことを示す好例なのです。具体的に言えば、デバッグ・メッセージがありません。このページを Apache で実行すると、まったく何も出力されません。バグが明白でなければ、どうやって悪い部分を見つけるのでしょう。

従来の解決方法としては、エラー・ログを調べます。例えば、Apache 2 を実行する Linux システムにこのページをロードする前に下記を実行すると、

tail -f /var/log/httpd/error_log

下記のようなものが出力されます。

[client 127.0.0.1] PHP Parse error:  parse error, unexpected T_STRING, expecting 
    '(' in /var/www/html/dont-code-drunk.php on line 2

残念ながら、このソリューションはとても理想的ではないと考える私の意見に、皆さんは賛成するかもしれません。第 1 に、ファイル・ログの場所がシステムによって変わる可能性があります。また別の問題として、必要なものを見つけるために無関係なイベントのログをたどらなければなりません (これはライブ・サーバーでは悪夢です)。

これを見れば、おそらく皆さんも私と同じように、もっと良い方法があるに違いないと考えることでしょう。


CLI を使ってエラーを発見し、修正する

上記のコードの問題は、CLI 上で直接スクリプトを実行することで容易に分離することができます。そのためには下記を実行します。

php dont-code-drunk.php

そうすると、下記のような出力が得られるはずです。

PHP Parse error:  parse error, unexpected T_STRING, expecting 
    '(' in /var/www/html/dont-code-drunk.php on line 2
Content-type: text/html
X-Powered-By: PHP/4.3.11

こちらの方がずっと適切です。エラー・メッセージは他のデータから分離されており、ページに変更を加えた場合には容易にページを再チェックすることができます。この場合では、行のどこかに '(' が必要なことが明確にわかります。その場所としては while 文が適切と思えるので、新しい 1 組みの括弧を追加し、次のようなソースにします。

#!/usr/bin/php -q
Don<'t>code<?php while (drunk()); ?<

これで再度コードを実行すると、下記の出力が得られます。

リスト 1. 再実行の結果
Content-type: text/html
X-Powered-By: PHP/4.3.11

<'t>codePHP Fatal error:  Call to undefined function:
    drunk() in /var/www/html/dont-code-drunk.php on line 2

このスクリプトには他にも山ほど問題がありますが、少しは進歩しました。比較的簡単に必要なエラー・メッセージを拾い出すことができ、それによってプログラム中の問題を素早く修正でき、次の問題に進めるようになりました。

PHP を使う人は誰でも、このようにしてデバッグに CLI PHP を活用することができます。では、さらに進めて、本物のシェル・スクリプトを PHP で作ったらどうなのでしょう。恐れず前進すると、単純な、そしてあまり単純ではないシェル・スクリプトにも、PHP を使えることがわかります。


PHP の I/O チャネル

最初の PHP スクリプトの目標は、最初は単純にしましょう。ここではファイルを読み取り、そのファイルの中の行をシャッフルします。この機能は、m3u ファイルなどをシャッフルする際に便利です。このためには、ファイルまたは標準入力から読み取り、端末に書き出せる必要があります。

ここでまず、PHP の一般的な問題に直面します。PHP は元々、キーボードからの直接入力や、ユーザーへのテキスト出力用には設計されていません。この設計を理解することは重要です。つまりコマンド・ラインで何かをしようとする場合には、ユーザーと対話動作できる必要があるのです。C など従来のプログラミング言語では、STDIN や STDOUT、STDERR などを使ってそれを実現します。PHP でも同じチャネルを、それぞれ、入力チャネルに、標準出力チャネルに、エラー出力チャネルに使用することができます。

STDOUT: echo、print、STDOUT、そして php://stdout

PHP はブラウザーに出力するために設計されており、CLI に出力するためには設計されてはいませんが、PHP から出力を作成するのはとても簡単なため、ほとんど考える時間は必要ありません。PHP タグの外で与えられるものはすべて、直接 CLI に出力されることを思い出してください。そのため、先ほどの HelloWorld プログラムはあれほど単純だったのです。また、エラー・メッセージが出力される前に上記の Don<'t>code が出力されたのも同じ理由からです。単語を HTML タグで囲むかどうかは関係なく、いずれにせよ単語は表示されるのです。実際、HTML タグはユーザーに直接出力されるため、一般的には HTML タグを避ける必要があります。

出力には、基本的な関数を使うこともできます。例えば、echo コマンドと print コマンドは、標準出力に出力します。

#!/usr/bin/php -q
Output #1.
<?php echo "Output #2.";
print "Output #3."?>

上記の結果は次のようになります。

Output #1.
Output #2.Output #3.

PHP タグ外の改行は出力されますが、echo コマンドや print コマンドには暗黙的な改行はないことに注意してください。実際、Output #2.Output #3. とすると、同じ行にコマンド・プロンプトが繰り返し表示されます。これに関しては、PHP が持っている他の出力関数も、あるいはファイルに書き込む関数も、同様に適切に動作します。

#!/usr/bin/php -q
<?php
        $STDOUT = fopen("php://stdout", "w");
        fwrite($STDOUT, "Output #1.");
        fclose($STDOUT);
?>

上記のコードは、php://stdout を明示的に出力チャネルとして開きます。また php://output は、一般的に php://stdout と同じように動作します。最近のバージョンの PHP では、上記の使い方のように変数 $STDOUT を定義するのではなく、STDOUT を定数として使うことができます。

STDERR: STDERR と php://stderr

STDERR は STDOUT と非常に似ています。このチャネルへの書き込みに使われる方法は、どれも STDOUT に使われる方法と同じです。唯一の違いは、php://stdout あるいは php://error を開く代わりに php://stderr を開くことです。

STDIN: STDIN と php://stdin

Web プログラミングとは異なるものの中で、STDIN は最も興味深いものです。STDIN によって、フォームや他のブラウザー・ベースの方法を使わずに、本当にユーザー入力を受け付けられるのです。次のコマンドを試してみてください。

#!/usr/bin/php -q
<?php
        $file = file_get_contents("php://stdin", "r");
        echo $file;
?>

このコマンドは cat とほとんど同じように動作し、与えられたすべての入力をエコー・バックするはずです。しかしこの場合は引数を受け付けません。


最初の PHP シェル・スクリプト

さて、ここからが面白いところです。これまでに得られた簡単な知識を活用すると、単純でありながら便利なシェル・スクリプトを作成できるのです。下記のコードをテキスト・エディターに入力してみてください。

リスト 2. 行をランダム化する
#!/usr/bin/php -q
<?php
        $lines = split("\n", file_get_contents("php://stdin", "r"));
        shuffle($lines);
        foreach ($lines as $line) {
                if ($line !== "") {
                        echo "$line\n";
                }
        }
?>

このスクリプトを動作させるには、下記のいくつかの点をチェックします。

  1. hashbang (#! で始まる最初の行) が、先ほど触れたように PHP 実行可能ファイルの場所に設定されていることを確認します。
  2. このファイルを保存します。
  3. chmod を使って実行可能パーミッションを追加します。
  4. プログラムを実行します。

行のランダム化が、まさに期待したとおりに動作することに注目してください。つまり、入力される行をシャッフルし、入力とは異なる順序で出力します。これは、シェル・スクリプト・ライブラリーには無い貴重な機能です。

このスクリプトの応用例として、音楽プレーヤーやビデオ・プレーヤーのランダム・プレイリストをすぐに作成することができます。例えば XMMS プレイリストをシャッフルするために、下記を試してみてください。

./randomize-lines < .xmms/xmms.m3u > temp
mv temp .xmms/xmms.m3u

最後に、もう 1 ステップ追加しましょう。


コマンド・ライン引数

本物のコマンド・ライン・プログラムは引数を使います。これに関しても、C などの言語と同様、argv と argc を使うことができます。特に、argv はプログラムに対する引数の配列であり、最初の引数はプログラムそのものです。これを使えば、与えられる引数に基づいてファイルやユーザー入力から読み取るプログラムを作成するのは難しくありません。例えば、下記のコードを見てください。

リスト 3. 引数を使って行をランダム化する
#!/usr/bin/php -q
<?php
        array_shift($argv);
        if (count($argv) == 0) {
                $argv[0] = "php://stdin";
        }
        foreach ($argv as $file) {
                $lines = split("\n", file_get_contents($file, "r"));
                shuffle($lines);
                foreach ($lines as $line) {
                        if ($line !== "") {
                                echo "$line\n";
                        }
                }
        }
?>

これで完成しました。ユーザー入力、あるいはファイルのリストを受け付け、各ファイルの関連する内容をランダム化する、完全動作の CLI PHP プログラムができたのです。


まとめ

作業に適したツールを選ぶことは重要ですが、最適なツールが予想外のものであることも多いことを忘れないでください。コマンド・ライン・インターフェースとして PHP を試してみると、PHP が皆さんお気に入りのシェル・スクリプト・ツールになるかもしれません。最悪の場合でも、Web サーバーに関する頭痛を軽減してくれるはずです。

参考文献

学ぶために

  • PHP by example」を読み、複雑で強力な Web 関連プログラムを PHP を使って簡単に作成する方法を学んでください。
  • PHP Freaks は CLI に関して PHP を議論しています。
  • PHP CLI は独自の Web サイトを持っています。誰か知っていましたか?
  • PHP.net は PHP 開発者のためのリソースです。
  • Recommended PHP reading list」を調べてみてください。
  • developerWorks には、他にも PHP に関する資料が豊富に用意されています。
  • IBM developerWorks の PHP project resources を利用して、PHP のスキルを磨いてください。
  • developerWorks podcasts では、ソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • IBM オープンソース開発者にとって関心のある、世界中で今後開催される会議や業界展示会、ウェブキャスト、その他のイベントについて調べてみてください。
  • developerWorks の Open source ゾーンをご覧ください。オープンソース技術を使った開発や、IBM 製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。
  • Safari Books Online にはオープンソース技術に関するリソースが豊富に取り揃えられています。

製品や技術を入手するために

  • 皆さんの次期オープンソース開発プロジェクトを IBM trial software を使って革新してください。ダウンロード、あるいは DVD で入手することができます。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=249832
ArticleTitle=コマンド・ライン PHP? もちろん可能です!
publish-date=03132007