Funciones de ejecución de programas

Notas

Advertencia

Los archivos abiertos con seguridad (especialmente sesiones abiertas) deben ser cerrados antes de ejecutar un programa en segundo plano.

Ver también

Estas funciones están también estrechamente relacionadas con el operador de comillas invertidas.

Tabla de contenidos

  • escapeshellarg — Escapar una cadena a ser usada como argumento del intérprete de comandos
  • escapeshellcmd — Escapar meta-caracteres del intérprete de comandos
  • exec — Ejecutar un programa externo
  • passthru — Ejecuta un programa externo y muestra la salida en bruto
  • proc_close — Cierra un proceso abierto mediante proc_open y devuelve el códido de salida de tal proceso
  • proc_get_status — Obtiene información sobre un proceso abierto por proc_open
  • proc_nice — Modificar la prioridad del proceso actual
  • proc_open — Ejecuta un comando y abre un puntero de fichero para entrada/salida
  • proc_terminate — Mata un proceso abierto mediante proc_open
  • shell_exec — Ejecutar un comando mediante el intérprete de comandos y devolver la salida completa como una cadena
  • system — Ejecutar un programa externo y mostrar su salida
add a note

User Contributed Notes 33 notes

up
9
valqk at lozenetz dot org
19 years ago
If you are chrooting php into enviornment that doesn't have /bin/sh you can't execute any command! Even when you call
mail() and it calls sendmail ... well actually sendmail NEVER gets called because /bin/sh is not in the chroot!
SO in conclusion: YOU MUST HAVE /bin/sh TO EXECUTE SOMETHING!!!
VERY IMPORTNAT!
I've lost few days while find this, hope it helps someone!!!
up
2
sam at freepeers dot com
20 years ago
To clarify even more about what has been said in the last few posts:

"exec", "backticks", "system" and so on will fail on Windows 2003 by default.

You must modify the security on cmd.exe to give the user account IUSR-computername the necessary permissions which are at least read & execute.
up
1
onkelfilemon at gmail dot com
4 years ago
Note that `popen` is also a program execution function, which for some reason is not listed here.
up
1
jpgiot at ifrance.com
21 years ago
FOR WINDOWS USERS

i had a look to start command. it's really usefull in fact.

this is how i launch a specific Apache SSL server

<?php
$cmd
= "start /D C:\OpenSA\Apache /B Apache.exe -D SSL";
exec($cmd,$output,$rv);
?>

/D specify the path where application will be launched (equivalent to cd to path)
/B launch application without a console window

so to know the exact parameters of start, you could use

<?php
exec
("start /? > start.txt");
?>

and you will get the help of start in a file named 'start.txt' in the same place you run the script

for WIN 98 you may need to modify a little your command

exec("COMMAND.COM /C START program args >NUL");

(taken from another post)
up
2
not at any dot com
18 years ago
at LAST! tenacity pays off, days trying every little thing!

I didn't want batch files. I'm trying to use PHP to get rid of batch files.

I didn't want to call a file to parse the parameters to call a shell to call a file. I've got "systems" right now with batches tiered three and five deep.

I just wanted to run stuff.

CALL, tested on WinXP, will be testing on more OSes right away, in PHP4 and 5, with exec, system, works with popen, and passthru.

here is my lame sample function.

// CreateZip
function createzip ($target, $archive)
{ $ziputil = "call \"c:\\Program Files\\7-zip\\7z.exe\"";
$archived = escapeshellarg($archive);
$targeted = escapeshellarg($target);

$shellcommand= $ziputil." a -tzip ".$archived." ".$targeted."\n";

// all of the below are working in Win XP Pro
passthru ($shellcommand);
exec ($shellcommand);
system ($shellcommand);
shell_exec ($shellcommand);
$proc= popen ($shellcommand, "r"); //$proc contains output

LONG PATH NAMES WITH SPACES IN THEM ON WINDOWS!

all in a big long concatenated command line with multiple quoted-filename parameters

shell scripting bliss!
up
1
leaetherstrip at inbox dot ru
20 years ago
Note on XP users: XP-Home edition does not allow to set rights directly on files and folders. You should use cacls command-line utility to do this.

For example:

cacls c:\windows\system32\cmd.exe /E /G IUSR_ADMIN2003:F

gives IIS user full access to cmd.exe (potential security hole!), so PHP can fork and execute external programs.
up
1
dotpointer
20 years ago
Win32 / PHP 4.3.6...

If you plan to start programs on the server that show message boxes (things that require OK from the server-side), or remain (like notepad.exe), and the exec-command seems to go into an deadly loop, then MAYBE your program has started, but you can't see it. Because the web server runs as an system process, and it isn't allowed to interact with the desktop.

To solve a part of the problem (to see the programs you execute), in the control panel in Windows, goto Administration->Services, right-click the server-service, goto Properties and on the second tab (login?) and check the box about allowing the service to interact with the desktop. Click OK. Restart the webserver, and MAKE SURE it is restarted for real (i.e. look in the task manager so the service goes _down_), otherwise the desktop-option won't take.

Next phase would be to stop PHP from waiting for the processes to complete (this is what makes PHP "loop"). I solved this by creating a small Delphi-application that took the path to the file I wanted to execute and executed it by the WinExec API, which just starts the childprogram but doesn't wait for it to complete = the program completes and the PHP.exe completes the script. Problem solved!

Delphi-snippet:
WinExec(PChar(<CMD>),SW_SHOW); // replace <CMD> with the program path.
up
0
Anonymous
16 years ago
I found this comment on this page:

[begin of quote]
Trying to us the following code failed badly with various results: like "unable to fork", "access denied", "empty results", depending on what settings I used, ... even though the same code worked from command line on the server itself.

$retstr = exec('nslookup -type=mx myhost.com', $retarr);

Instead of nslookup I believe this would apply to most programs from the \system32\ directory.

I had to learn that the following finally worked:
$retstr = exec('c:\php\safedir\nslookup -type=mx myhost.com', $retarr);

... but only under the listed preconditions:
1: nslookup.exe is placed (copied) in the directory \php\safedir\
2: the directory \php\safedir\ is included in the system PATH environement variable
3: the file cmd.exe is placed in \php\ as listed by other notes above
4: the directory "c:\php\safedir\" is set in the php.ini setting
safe_mode_exec_dir = "c:\php\safedir\"
.. maybe set in php-activescript.ini as well, depending on your system setup.
5: nslookup is referenced by the full path as otherwise the file from \windows\system32\ will be called. This happend to me with empty result due to missing rights!

Hope this helps somebody saving some time and headaches.
[end of quote]

This is just to complicated. Only two things are needed:
1. Specific permissions for the IUSR account for read & execute to the cmd.exe in C:\Windows\System32 directory
2. Specific permissions for the IUSR account for read & execute to the command that's needed (example: nslookup.exe in C:\Widnows\System23 directory)

With just this two conditions the exec works fine

(This is for an IIS server running on a windows platform)
up
0
mosesdinakaran at yahoo dot co dot in
16 years ago
Hi

I had problem with executing exec(),shell_exec() (PHP is not running on Safe Mode).

After spending some time I was able to find out that the Problem is with SELinux enabled in my system.

You can make sure about this by seeing the log /var/log/messages
So I disabled SELinux and now everything works.

A Temporary Disable to selinux #> setenforce 0;

Since I felt this is not a good Idea I still went through some sites and find a solution which I felt good.

Fedora's SELinux policy has some booleans - let's see what it has for our apache:
# /usr/sbin/getsebool -a | grep httpd
allow_httpd_anon_write -- off
allow_httpd_mod_auth_pam -- off
allow_httpd_sys_script_anon_write -- off
httpd_builtin_scripting -- on
httpd_can_network_connect -- off
httpd_can_network_connect_db -- off
httpd_can_network_relay -- off
httpd_disable_trans -- off
httpd_enable_cgi -- on
httpd_enable_ftp_server -- off
httpd_enable_homedirs -- on
httpd_rotatelogs_disable_trans -- off
httpd_ssi_exec --off
httpd_suexec_disable_trans -- off
httpd_tty_comm -- off
httpd_unified -- on

From the above we can make sure that exec() is not working because of this httpd_ssi_exec -- off setting
So I turned it On.

#> setsebool -P httpd_ssi_exec 1;

Now I was able to see the output of shell_exec('ls -al')

Moses
up
0
luko post cz
16 years ago
to lancelot:

it's simple exec($my_cmd) on windows executes 'cmd /c $my_cmd'
if there are any spaces in $my_cmd you have to put it in doublequotes:
cmd /c "$app $target" will work

further if there are any spaces in $app and $target they also have to be in doublequotes:
cmd /c ""$app" "$target""

therefore enclose your $cmd in two more doublequotes and dont forget to escape slashes \\

$cmd = "\"\"C:\\my path with spaces\\targetapp.exe\" \"C:\\mypathnospaces\\targetfile.xxx\"\"";

and exec($cmd) will work :)
no chdir anymore...
up
0
jakster at gmx dot net
16 years ago
To fork a process I use the following code

<?php

fclose
(STDOUT); //Close all output or it WON'T work
fclose(STDIN);
fclose(STDERR);

if(
pcntl_fork()) {
exit;
//Return to the caller
}

//Code to run in the background

pcntl_exec("/usr/bin/php",Array($_SERVER['argv'][1]));

?>

I call this script from my website with
<?php
function fork($script){ //run a forked php script relative to the document root. NO OUTPUT IS DISPLAYED!
global $config;
$cmd = "/usr/bin/php \"" . dirname($_SERVER['SCRIPT_FILENAME']) . "/includes/forked/forkHelper.php\" \"" . $script . "\"";
exec($cmd);
}
?>
up
0
steve dot robinson at frogneck dot com
17 years ago
If you are trying to use exec to run a cgi and output the contents via a php file, headers need to be seperated from the content and output seperately.

Also, at least in the case of the cgi I was attempting to execute, line feeds were missing, and some javascript didn't work as a result, so you may have to add line feeds back into the resulting output. Here is the code I used to output my cgi properly...

<?PHP
putenv
('REQUEST_METHOD=GET');

// to get your parameters passed into the cgi..
putenv('QUERY_STRING=' . $_SERVER['QUERY_STRING']);

//you will know you are past the header when you
//hit a blank line ('')
$inheader=true;
foreach(
$output as $val){
if(
$val=='')
$inheader=false;
if(
$inheader)
header($val);
else
echo(
$val . "\n"); // output contents
}
?>
up
0
php at fendy dot org
17 years ago
Scheduling WinXP tasks with schtasks.exe and using PHP to execute the command, may sometime fail to work.

This is because, Apache does not have the privilege to access some of the System Files when placing the scheduling. The way I'd do: is by creating a normal user account and assign Apache service to logon as that account.

Open the 'services.msc' in the 'Run' window, look for Apache in the listing, right click and get to 'Properties'. Click at the second tab 'Log On' and fill in the 'This account' fields.

Of course, Apache needs to be installed as Service during its first setup.

Hope this helps anyone.

Fendy Ahmad
up
0
Anonymous
17 years ago
it seams to me the best way would be to copy cmd.exe to a secure directory somewhere under your web directory, add it to the windows path and then call it from there using system commands. It seams as though that would get arround any security holes
up
0
Matt-kun
18 years ago
Just a simple note to help people get rid of some headaches.

when using:
<?
$filepath = "the path of the file";
exec("program -command $filepath ");
fopen($filepath,rw);
?>

Make sure you use "\ " ( \ space) for the Linux\unix path and just " " space for fopen. These are both very basic things that you wouldn't normally think to cause a problem, but when you try to pass slashes to fopen it either breaks or even better works incorrectly =D. And vise versa for any programs that use "\ " for spaces in file paths/names.

I ran into this problem when using <? exec(" cp $path "); ?> and <? fopen("$path"); ?>. To fix it I used str_replace(" ","\ ",$path); and str_replace("\ ", " ",$path);

*Note this is alot of sudo code, and there are faster more effecient ways of doing the same operations, but I thought this might help those who were going crazy over filepaths =D.
up
0
judas dot iscariote at gmail dot com
18 years ago
This functions are generally considered harmful,without proper input validation procedures are as worse as eval().

If what you are trying to do is possible using other mechanism, ** do it that way, even if it takes more time **.

Do not cry or blame PHP if your server gets "owned" due to a missing escapeshell*** in your code , you have been warned.
up
0
manokan at manokan dot net
19 years ago
Even more on the "unable to fork" error.

It was driving me crazy! I did check that the permissions were set for the IUSR_[server] account to read & exec cmd.exe. Yet still it failed. It wasn't until I got desperate that I happened to look in "special permissions." (Click the advanced tab underneath the regular list of permissions.) There I found that somehow the IUSR_[server] account had a special permission DENYING access! Of course deny overrides everything else.

This was a newly set up install of XP pro. It must be the default of something (I'd guess IIS) to set this deny permission just to make our lives miserable.
up
0
abhilashp at clariontechnologies dot co dot in
19 years ago
I faced the problem of putting a shell script as a backgroud process using both exec() and system() commands on a FreeBSD Server with PHP 4.4.0

I tried all the above mentioned methods but couldnt succeded, then i coded this script and am sure will work on all Linux flavors... See if ot helps you all guys...

I Put my Shell Script in the variable $ExecCommand

and used the proc_close and proc_open functions the code is as follows :

proc_close (proc_open ($ExecCommand,array(),$somefun));

After the above line the rest of the usual php script continues....

Hope it helps you guys..
up
0
margus at kohv dot com
19 years ago
Well, I had this issue when I wanted to start an indefinitely running PERL script from PHP. Somehow I could not make the PHP script to return after executing the PERL script. So finally I came to following solution:

PHP file
-------------------
<?php
exec
("perl /home/chatserver.pl > /dev/null");
?>
-------------------
This script will be run over HTTP.

PERL file
-------------------
#!/usr/bin/perl
fork and exit 1;

# normal code here...
-------------------

Hopefully it helps someone :)
Margus
up
0
sean @T keenio - dot - com
19 years ago
Just to clarify, background shell exec()ing is not the same as a fork() under Unix. It would be useful if PHP supported fork() like Perl and other scripting languages do. Simply exec()'ing a process and sending it to the background is not the same.

A true fork() copies the current environment and duplicates the running script so that there are two instances, one child, one parent. The child and parent can determine which copy they are and then take separate courses of execution paths based on that. Often one copy will perform some "busy work" while the other returns to normal execution. But no matter what, both functions live within the same code rather than a separate, external program. exec()ing can not do this for you.
up
0
vosechu at roman-fleuve dot com
20 years ago
Quick chart that helped me immensely (Best (+) / worst (o) of each command) and when to use each (w).

| exec(string cmd, [array cmd_output, [int cmd_exit_status]])
+- Second (optional) argument holds an array containing the output line by line.
+- Third (optional) argument holds the exit status of the executed program.
w- When the output of a command is only important to the program.

| system(string cmd, [int cmd_exit_status])
+- Echos ascii output straight to browser (only stdout; stderr must be redirected by putting 2>&1 after the command to see errors).
+- Second (optional) argument holds the exit status of the executed program.
w- When the output of a command is important to the user.

The more I go over my notes the less I care for the last two functions.
Shell_exec() = exec() + implode() - exit codes.
And while neccessary to be able to pipe binary through php, most people will never use passthru

| passthru(string cmd, [int cmd_exit_status])
+- Echos binary output directly to browser window.
+- Second (optional) argument holds the exit status of the executed program.
w- When the output of a command is binary.

| shell_exec(string cmd) <-- minimal features to maintain sync with normal use of backticks.
+- Returns full output as a string instead of directly to the browser (only stdout; stderr must be redirected).
o- No way to check exit status (Should use system() with both stderr and stdout redirected to /dev/null to get the exit code).
up
0
ferchland at computer-kontor dot de
20 years ago
I tried to fork a GUI-process on WinNT, Apache 2, PHP4.
I saw the new process (notepad.exe) in the Task-Managers process-list, but no Notepad-Window anywhere!
After activating the checkbox "Interactive with Desktop allowed" in Services->Apache everthing works with a simple command
exec("start c:\\winnt\\notepad.exe");
up
0
dens at dodgeball dot com
21 years ago
I was stuck for about an hour and a half last night trying to get Perl to pass back values to my PHP script after running an exec() command.

Since my Perl script was using STDOUT (after being passed command lines variables), I expected the variables used in my .pl script to be accessible in PHP, no questions asked.

Of course, this wasn't working and I finally figured it out with the help of a friend (Shawn = superstar): you need to echo the exec() command in order to get the values back into PHP.

Since I was returning multiple values, I added pipe delimiters in my .pl script and then used PHP to parse the string to retreive my data into different variables.

Check it out:

#hit the .pl script with the data
$mydata = exec("script.pl 'command line args' ");
exec("exit(0)");

#parse the value that comes back from the .pl script
list($strA, $strB) = split ('[|]', $mydata);
echo "valueA: " . $strA."<br>";
echo "valueB: " . $strB."<br>";

Woo-hoo!
/d
up
0
software at yvanrodrigues dot com
21 years ago
MORE ON THE UNABLE TO FORK MESSAGES IN WINDOWS:

I would like to confirm that this issue relates to permissions on %SYSTEMROOT%\SYSTEM32. The user (usually the anonymous login) must have execute permissions on cmd.exe

This is unlike most other programming languages. For example, in C the spawn and exec functions do not try to open a shell, they create the new process directly. PHP creates the new process via cmd.exe (or command.com) much like the C system() function. This is good for those of you who are trying to run batch files but this is very ineffecient for running other .exe files.

I feel uneasy about lifting permissions in my system32 directory but you can get around this by copying cmd.exe to your PHP directory. Windows will look there first and if it is not there it will check the path. Note: I mean the directory where php.exe is, not your script directory.

I have confirmed this by running filemon.exe while trying to execute a script, and you can see it trying to start the cmd.exe process.
up
0
qscripts at lycos dot nl
21 years ago
Why not using the "start" utility, provided with every version of Windows to start processes in the background on Windows machines? For example :

exec("start song.mp3");

Which will cause the default handeling application for .MP3 file types to start playing the selected song..
up
0
kop at meme dot com
22 years ago
AFICT, the standard Unix Apache configuration causes an rare problem when running a job in the background. The MaxRequestsPerChild directive causes the child to terminate after 1000 requests, any background processes associated with the child will die with the child unless they are started with the "nohup" command. Thus, the proper way to start a job in the background is to use:

exec('nohup my-command > /dev/null 2>&1 &')
up
0
ramirosuarez at fibertel dot com dot ar
22 years ago
For Windows Users:

Keep in mind that a lot of UNABLE TO FORK Errors are the result of insufficient permissions.

CMD.EXE, TEMP Directory (or whatever you specified in php.ini), and all the directories that you use to upload o manipulate your files need to have Write privileges? usually user USER.

This will be useful for all the people who use GD Libraries or other programs that manipulate graphic images.
up
0
GCMXZPJPDJER at spammotel dot com
22 years ago
to execute a script in background from php you don't need to use mikehup or other tools. just do:

`/usr/bin/php -q foobar.php >/dev/null 2>&1 &`;

mat
up
0
daniel dot hopp at godot dot de
22 years ago
Re: session_write_close()

To launch a background process within a session, I recommend
to use a start-stop-daemon and ship parameters via ENV.

Example:
----------------------------------------
<?php
// Within a session..
exec("/some/where/launch.sh 300");
// ..finished immediately.
?>

----------------------------------------
#!/bin/bash
# /some/where/launch.sh
T=$1
export T
DAEMON=/some/where/runme.pl
start-stop-daemon --start --quiet --background --exec $DAEMON

----------------------------------------
#!/usr/bin/perl
# /some/where/runme.pl
my $t = $ENV{'T'};
sleep($t);

----------------------------------------
up
-1
manokan at manokan dot net
18 years ago
Lets make it even clearer, about the "unable to fork" error in exec().

By default Windows XP sets all permissions for cmd.exe for the temporary internet user account (IUSER-[computername]) to DENY. That overrides everthing.

You must modify the security on cmd.exe to give the IUSER-computername account at least read & execute and remove the DENY.
up
-1
Shaun
19 years ago
Trying to use 'exec' to run a helper executable on Win2K3 (and I'm told this also happens on Win2K) from a PHP script running on IIS, failed to invoke the executable.

Running the same PHP script on Win2K using Apache to serve the page calling the same helper executable worked.

Solution: On Win2K3 (and probably Win2K), give the IIS IUSR_xxxxx guest user Read & Execute permissions to Cmd.exe found in the System32 folder under Windows root directory.

This one had me confused longer than it should have! Hope this saves others from the same fate!
up
-1
kristof_jebens at hotmail dot com
21 years ago
For WIN2K Server users running Apache 1.3.22 who are unable to run an executable...

exec('c:\\WINNT\\system32\\cmd.exe /c START c:\\file.exe');

this is the only way it worked for me.
Hope that helps
up
-1
deschampsbest at noos dot fr
22 years ago
I needed to know when a group of background tasks, which had been launched with a call to system, had terminated.
I could not find a function to call, so I created a little function.

It basically loops on the existance of a string in the results returned by the command ps.

All my commands, which run in background have the pid returned by posix_getpid in them.

I am able to launch many background task and effectively wait for them all to finish.

Before this, I would basically would sleep for N seconds.

I apologise if a well known or better method exist.

Thanks,
The New Bee
===============
===============

function wait_until_termination ($id, $duration){
$i = 0;
do {
$i += 1;

$cnt = `ps -auxww |
grep $id |
grep -v grep |
awk '{print $2}' |
grep -v $id|
wc -l` ;

if ($cnt > 0) {
sleep ($duration);
}

} while ($cnt != 0);

echo ("wait_until_termination (PID: $id, SEC: $duration) : LOOPS
:$i<BR>");
}
To Top