web-dev-qa-db-ja.com

PHPでシェルスクリプトを実行する方法

/ var/www/myscript.shにスクリプトがあります。これはフォルダーを作成し、プロジェクト用にsvn updateコマンドを実行します。ブラウザでPHPファイル(Localhost/test.php)で呼び出すことにより、このスクリプトを実行する必要があります。関数Shell_exec()およびexec()が動作しませんでしたsu www-data && ./myscript.shを使用して端末でシェルスクリプトを実行しましたが、動作しました。

<?php
$output = Shell_exec("./myscript.sh");
?>

2011年5月4日更新:

www-data ALL=(ALL) NOPASSWD:ALLを/ etc/sudoersに追加しましたが、動作しますが、これは非常に安全ではありません。これを行う別の方法はありますか?

21
Rakesh

いくつかの可能性:

  • セーフモードが有効になっています。そうすれば、exec()のみが機能し、 _safe_mode_exec_dir_ の実行可能ファイルのみで機能します
  • execと_Shell_exec_はphp.iniで無効になっています
  • 実行可能ファイルへのパスが間違っています。スクリプトがphpファイルと同じディレクトリにある場合は、exec(dirname(__FILE__) . '/myscript.sh');を試してください
12
Residuum

Exec特権を無効にした可能性がありますが、ほとんどのLAMPパッケージではこれらの特権が無効になっています。 php.iniで次の行を確認してください。

disable_functions = exec

Exec、Shell_execエントリがある場合は削除します。

がんばろう!

Residuumは、Shell execを使用してスクリプトを見つける方法について正しい答えを提供しましたが、セキュリティに関しては、いくつかのポイントがあります。

サーバーにWebアクセスできる人なら誰でも見ることができるので、ShellスクリプトをWebルートに入れたくないと思います。

シェルスクリプトをwebrootの外部に移動することをお勧めします

    <?php
      $tempFolder = '/tmp';
      $webRootFolder = '/var/www';
      $scriptName = 'myscript.sh';
      $moveCommand = "mv $webRootFolder/$scriptName $tempFolder/$scriptName";
      $output = Shell_exec($moveCommand);
    ?>

に関して:

www-data ALL =(ALL)NOPASSWD:ALLを/ etc/sudoers worksに追加しました

これを変更して、Sudoを必要とするスクリプト内の特定のコマンドのみをカバーできます。それ以外の場合、shスクリプト内のコマンドのいずれもSudoの実行を必要としない場合、とにかくこれを行う必要はありません。

Apacheユーザーとしてスクリプトを実行してみて(suコマンドを使用してApacheユーザーに切り替えます)、Sudoのプロンプトが表示されなかったり、許可が拒否されたりした場合は、問題ありません。

すなわち:

Sudo su Apache (or www-data)
cd /var/www
sh ./myscript

また...ここに来たのは、動的に生成されるコマンドを使用して複数行のシェルスクリプトを実行したかったということです。すべてのコマンドを同じシェルで実行したかったのですが、Shell_exec()を複数回呼び出しても発生しません。その答えは、Jenkinsのようにすることです-動的に生成されたコマンドの複数行を作成し、変数に入れ、一時フォルダーのファイルに保存し、そのファイルを実行します(JenkinsのようにShell_exec in()phpを使用してJava)、出力で必要なことを行い、一時ファイルを削除します

...出来上がり

6
Pharaoh Tools

実行する必要のある小さなスクリプトがある場合(ファイルをコピーするために必要なだけです)、PHPスクリプトを呼び出してコマンドを呼び出す方がはるかに簡単であることがわかりました

exec("Sudo cp /tmp/testfile1 /var/www/html/testfile2");

そして、最初にSudo visudoおよび次の行を最後に追加します

www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/testfile1 /var/www/html/testfile2

私がやりたかったのはファイルをコピーすることだけでしたが、ルートパスワードの問題のためにコピーに問題がありました。あなたが言ったように、すべてのルートトランザクションに対してパスワードを持たないようにシステムを公開したくありませんでした.

1
Babak D