PHPのお勉強!

PHP TOP

exec

(PHP 4, PHP 5, PHP 7, PHP 8)

exec外部プログラムを実行する

説明

exec(string $command, array &$output = null, int &$result_code = null): string|false

exec() は指定されたコマンド command を実行します。

パラメータ

command

実行するコマンド

output

引数 output が存在する場合、指定した配列は、 コマンドからの出力の各行で埋められます。 \n のような後に続く空白は、この配列には含まれません。 配列に既に何らかの要素が 含まれる場合は、exec() は配列の最後に追加される ことに注意してください。関数が要素を追加することを望まないのなら、 それが exec() に渡される前に、配列の unset() を呼び出してください。

result_code

引数result_codeが、引数 output と共に存在する場合、実行したコマンドの ステータスがこの変数に書かれます。

戻り値

コマンド結果の最後の行を返します。コマンドを実行し、 一切干渉を受けずに直接コマンドから全てのデータを受けとる必要が あるならば、passthru() 関数を使ってください。

失敗時に false を返します。

実行されたコマンドの出力を取得するには、必ず output パラメータを設定・使用してください。

エラー / 例外

exec()command を実行できない場合、E_WARNING が発生します。

command が空だったり、null バイトが含まれている場合、 ValueError がスローされます。

変更履歴

バージョン 説明
8.0.0 command が空だったり、null バイトが含まれている場合、 ValueError がスローされるようになりました。 これより前のバージョンでは、 E_WARNING が発生し、false を返していました。

例1 exec() の例

<?php
// ("whoami" コマンドをパスに有するシステム上で)
// 実行中のphp/httpdプロセスを所有するユーザーの名前を出力
$output=null;
$retval=null;
exec('whoami', $output, $retval);
echo
"Returned with status $retval and output:\n";
print_r($output);
?>

上の例の出力は、 たとえば以下のようになります。

Returned with status 0 and output:
Array
(
    [0] => cmb
)

注意

警告

ユーザーが入力したデータをこの関数に 渡すことを許可する場合、ユーザーが任意のコマンドを実行できるようシステムを欺くことが できないように escapeshellarg() または escapeshellcmd() を適用する必要があります。

注意:

プログラムがこの関数で始まる場合、 バックグラウンドで処理を続けさせるには、 プログラムの出力をファイルや別の出力ストリームにリダイレクトする必要があります。 そうしないと、プログラムが実行を終えるまで PHP はハングしてしまいます。

注意:

Windowsでは、exec() 関数はコマンドを起動するために最初に cmd.exe を起動します。cmd.exe を起動せずに外部プログラムを起動したい場合は、proc_open() 関数を bypass_shell オプションを指定して使うようにしてください。

参考

add a note

User Contributed Notes 22 notes

up
189
Arno van den Brink
16 years ago
This will execute $cmd in the background (no cmd window) without PHP waiting for it to finish, on both Windows and Unix.

<?php
function execInBackground($cmd) {
if (
substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
?>
up
84
dell_petter at hotmail dot com
15 years ago
(This is for linux users only).

We know now how we can fork a process in linux with the & operator.
And by using command: nohup MY_COMMAND > /dev/null 2>&1 & echo $! we can return the pid of the process.

This small class is made so you can keep in track of your created processes ( meaning start/stop/status ).

You may use it to start a process or join an exisiting PID process.

<?php
// You may use status(), start(), and stop(). notice that start() method gets called automatically one time.
$process = new Process('ls -al');

// or if you got the pid, however here only the status() metod will work.
$process = new Process();
$process.setPid(my_pid);
?>

<?php
// Then you can start/stop/ check status of the job.
$process.stop();
$process.start();
if (
$process.status()){
echo
"The process is currently running";
}else{
echo
"The process is not running.";
}
?>

<?php
/* An easy way to keep in track of external processes.
* Ever wanted to execute a process in php, but you still wanted to have somewhat controll of the process ? Well.. This is a way of doing it.
* @compability: Linux only. (Windows does not work).
* @author: Peec
*/
class Process{
private
$pid;
private
$command;

public function
__construct($cl=false){
if (
$cl != false){
$this->command = $cl;
$this->runCom();
}
}
private function
runCom(){
$command = 'nohup '.$this->command.' > /dev/null 2>&1 & echo $!';
exec($command ,$op);
$this->pid = (int)$op[0];
}

public function
setPid($pid){
$this->pid = $pid;
}

public function
getPid(){
return
$this->pid;
}

public function
status(){
$command = 'ps -p '.$this->pid;
exec($command,$op);
if (!isset(
$op[1]))return false;
else return
true;
}

public function
start(){
if (
$this->command != '')$this->runCom();
else return
true;
}

public function
stop(){
$command = 'kill '.$this->pid;
exec($command);
if (
$this->status() == false)return true;
else return
false;
}
}
?>
up
2
tsmtgdi at gmail dot com
1 year ago
Please be aware that EXEC ignore the stderr!

So something like

mkdir /impossible path

Will fail, and show nothing, you must use

mkdir /impossible 2>&1

to properly capture the error message

ELSE
if executed in CLI, will just print on the terminal, if executed on a browser is lost.

I strongly suggested those notes to be added in the main description, and not lost in a comment at the bottom.
up
45
Simon
10 years ago
Can’t get the output from your exec’d command to appear in the $output array?
Is it echo’ing all over your shell instead?

Append "2>&1" to the end of your command, for example:

exec("xmllint --noout ~/desktop/test.xml 2>&1", $retArr, $retVal);

Will fill the array $retArr with the expected output; one line per array key.
up
27
msheakoski @t yahoo d@t com
20 years ago
I too wrestled with getting a program to run in the background in Windows while the script continues to execute. This method unlike the other solutions allows you to start any program minimized, maximized, or with no window at all. llbra@phpbrasil's solution does work but it sometimes produces an unwanted window on the desktop when you really want the task to run hidden.

start Notepad.exe minimized in the background:

<?php
$WshShell
= new COM("WScript.Shell");
$oExec = $WshShell->Run("notepad.exe", 7, false);
?>

start a shell command invisible in the background:
<?php
$WshShell
= new COM("WScript.Shell");
$oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false);
?>

start MSPaint maximized and wait for you to close it before continuing the script:
<?php
$WshShell
= new COM("WScript.Shell");
$oExec = $WshShell->Run("mspaint.exe", 3, true);
?>

For more info on the Run() method go to:
http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp
up
9
Farhad Malekpour
17 years ago
If you're trying to use exec in a script that uses signal SIGCHLD, (i.e. pcntl_signal(SIGCHLD,'sigHandler');) it will return -1 as the exit code of the command (although output is correct!). To resolve this remove the signal handler and add it again after exec. Code will be something like this:

...
pcntl_signal(SIGCHLD, 'sigHandler');
...
...
(more codes, functions, classes, etc)
...
...
// Now executing the command via exec
// Clear the signal
pcntl_signal(SIGCHLD, SIG_DFL);
// Execute the command
exec('mycommand',$output,$retval);
// Set the signal back to our handler
pcntl_signal(SIGCHLD, 'sigHandler');
// At this point we have correct value of $retval.

Same solution can apply to system and passthru as well.
up
4
Paul Sommer
8 years ago
I tried to execute a command in background under Windows.
After struggling for hours with all these half ready examples I would like to share the syntax I found working (for windows at least). This is not tested under Linux as there are more elegant ways to spawn a process.

Based on the function from Arno van den Brink.

<?php
function execInBackground($cmd) {
if (
substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
?>

This works perfectly with e.g.
<?php
execInBackground
('del c:\tmp\*.*')
?>

but the following does NOT work:
<?php
execInBackground
('\"c:\path with spaces\my program.exe\"')
?>

Why?
When windows sees quotation marks (\") it thinks this is the window title, not the command.
So, when your command needs quotation marks you HAVE TO provide a window name first, like
execInBackground("\"title\"" "\"c:\path with spaces\my program.exe\")

Quotation marks are mandatiory for window title. Otherwise windows thinks this is the program name.

Weired, but "Hey! it's Windows!" :)
up
2
Bob-PHP at HamsterRepublic dot com
19 years ago
exec strips trailing whitespace off the output of a command. This makes it impossible to capture signifigant whitespace. For example, suppose that a program outputs columns of tab-delimited text, and the last column contains empty fields on some lines. The trailing tabs are important, but get thrown away.

If you need to preserve trialing whitespace, you must use popen() instead.
up
2
elwiz at 3e dot pl
14 years ago
On Windows-Apache-PHP servers there is a problem with using the exec command more than once at the same time. If a script (with the exec command) is loaded more than once by the same user at the same time the server will freeze.
In my case the PHP script using the exec command was used as the source of an image tag. More than one image in one HTML made the server stop.
The problem is described here (http://bugs.php.net/bug.php?id=44942) toghether with a solution - stop the session before the exec command and start it again after it.

<?php

session_write_close
();
exec($cmd);
session_start();

?>
up
2
Hypolite Petovan
4 years ago
On Unix, to execute a command $cmd in the background, the one and only allowed standard output redirection syntax is "> /path/to/file &". No other valid standard output redirection syntax will allow a command to be ran in the background.

<?php
// The following will be ran in the background
exec($cmd . " > /path/to/file &");

// All the following will NOT be ran in the background
exec($cmd . " >> /path/to/file &");
exec($cmd . " &> /path/to/file &");
exec($cmd . " &>> /path/to/file &");
exec($cmd . " 2>&1 > /path/to/file &");
exec($cmd . " 2>&1 >> /path/to/file &");
?>
up
2
hans at internit dot NO_SPAM dot com
22 years ago
From what I've gathered asking around, there is no way to pass back a perl array into a php script using the exec function.

The suggestion is to just print out your perl array variables at the end of your script, and then grabbing each array member from the array returned by the exec function. If you will be passing multiple arrays, or if you need to keep track of array keys as well as values, then as you print each array or hash variable at the end of your perl script, you should concatenate the value with the key and array name, using an underscore, as in:

foreach (@array) print "(array name)_(member_key)_($_)" ;

Then you would simply iterate through the array returned by the exec function, and split each variable along the underscore.

Here I like to especially thank Marat for the knowledge. Hope this is useful to others in search for similar answer!
up
2
php dot reg at kjpetrie dot co dot uk
2 years ago
If you want to run the command in the background and also use escapeshellcmd() as recommended, ensure you do the redirection outside the brackets! These are things you do want the shell to interpret.

E.g. exec(escapeshellcmd('mycommand and arguments').' > /dev/null &');
up
2
juan at laluca dot com
13 years ago
I was trying to get an acceslist from a remote computer by executing cacls and parse it in php, all in a Windows environment with Apache. First i discovered psexec.exe from Windows SysInternals.

But with the following line, I didn´t get anything, it get hunged, although from the command line it worked nice:

<?php exec ('c:\\WINDOWS\\system32\\psexec.exe \\192.168.1.224 -u myuser -p mypassword -accepteula cacls c:\\documents\\RRHH && exit', $arrACL ); ?>

To make it work I just followed the next steps:
- execute services.msc and find the apache service (In my case wampapache)
- Right button>Log On tab and change from Local System Account to a user created account, enter the username and the password and restart the service.

(I added this user to the administrators group to avoid permissions problems but its not recommended...)

It worked! And it may work with IIS too so try it if you have the same poblem....

Hope this helps someone, and sorry for my english
up
0
mamedul.github.io
1 year ago
Cross function solutions for execute command using PHP-

function php_exec( $cmd ){

if( function_exists('exec') ){
$output = array();
$return_var = 0;
exec($cmd, $output, $return_var);
return implode( " ", array_values($output) );
}else if( function_exists('shell_exec') ){
return shell_exec($cmd);
}else if( function_exists('system') ){
$return_var = 0;
return system($cmd, $return_var);
}else if( function_exists('passthru') ){
$return_var = 0;
ob_start();
passthru($cmd, $return_var);
$output = ob_get_contents();
ob_end_clean(); //Use this instead of ob_flush()
return $output;
}else if( function_exists('proc_open') ){
$proc=proc_open($cmd,
array(
array("pipe","r"),
array("pipe","w"),
array("pipe","w")
),
$pipes);
return stream_get_contents($pipes[1]);
}else{
return "@PHP_COMMAND_NOT_SUPPORT";
}

}
up
0