PHPからbash実行
PHPのソースコード内でLinuxのシェル(bash)を呼びたいことがよくある。例えば
A.ラジオを録音するためのこんな画面(recRADIO5.html)を開発していて
B.「録音開始」を押したら録音画面(recRADIO5.php)に推移し
C. 録音ファイルをいつでもどこでも聞くことができる
を実装しようとしているが、B.のときに画面が固まって困る。
より具体的には、B.でphpからLinuxシェル(bash)コマンドを呼んでいるのだが
そのbashコマンドの実行結果が返ってくるまで、PHPが画面を固まらせてしまっている。
解消法がわからなくてホトホト苦労したが、やっとやり方がわかった。
PHP からbashコマンドをノンブロッキング(非同期処理)で実行する方法
① bashコマンドの末尾にアンパサンド(&マーク)を付けてバックグラウンド実行する
② bashコマンドの出力は >> /dev/nullに捨てる
③ bashコマンドは必ずsudo実行する。でないと >> /dev/null に書き込めない!
→ phpがsudoコマンドを呼び出せる権限を持っているか(httpd.confまわりの)確認必要。
④ bashコマンドは、頭にshをつけて別シェルで実行する!でないとなぜかブロッキングかかる
⑤ php内から実行するbashコマンドは一旦 $command変数に格納してから shell_exec("$command"); としたほうがよい。
→ shell_exec()引数内に直接コマンドを書くとなぜかブロッキングかかる
ソース文字列はこんな感じ。
// ./folder1/folder2/rec_radiko2_2/rec_radiko2.sh JOAK 1 id_desu@gmail.com pass_desu /media/MUSIC JOAK > /dev/null 2>&1 &
// ./folder1/folder2/rec_radiko2_2/rec_radiko2.sh ' . "$myCH" . ' ' . "$myMIN" . ' ' . 'id_desu@gmail.com pass_desu /media/MUSIC' . ' ' . "$myCH" . ' > /dev/null 2>&1 &
$command = 'sh /folder1/folder2/rec_radiko2_2/rec_radiko2.sh ' . "$myCH" . ' ' . "$myMIN" . ' ' . 'id_desu@gmail.com pass_desu /media/MUSIC' . ' ' . "$myCH" . ' > /dev/null 2>&1 &';
順番にみていくと、まずは行末が大事で
$myCH" . ' > /dev/null 2>&1 &';
となっている。アンパサンド(&マーク)を使ってbashコマンドをバックグラウンド実行しているということだ(上記①)。
さらにまだ行末が大事で
$myCH" . ' > /dev/null 2>&1 &';
となっていて、出力をnullデバイスに捨てているのだが(上記②)、そのためにはnullデバイスを使える権限が必要なわけで、つまりsudoで実行しなければいけない(上記③)。今回はなぜかsudoなしで成功したが、うまくいかないときは「bashコマンド先頭にsudoをつける」をとりあえずやってみるのが良さそう。
最後は行頭に目をやると、
$command = 'sh /folder1/folder2/rec_radiko2_2/rec_radiko2.sh '
となっていて、ラジコ録音スクリプト(rec_radiko2.sh)を、別のシェルで実行させるために頭にshを持ってきているのが分かる(上記④)。
シェルコマンドの実行方法はこの本にまとまっている。
Linuxシェルコマンドでは他の追随を許さない最良の本だと思う。 改訂第3版が最新だけど、改訂新版でもほぼ同じだから、中古でもなんでもいいから1冊は持っておくといいと思う。
いやはや、今回はやりたいことの情報がGoogleですら取れなくて苦労した。
PHP ノンブロッキング bash で検索しても、全くそれらしい情報に当たらないし。
PHP バックグラウンド実行 bash で検索して、やっとこのへんが参考になった。
PHPでの非同期処理はnode.jsが常道らしいが、
単にbashコマンドを実行したいだけなのにnodeサーバを立てること自体がだるいので、今回は参考程度にしておいた。