程序执行函数

注意

警告

在后台执行程序之前,应关闭带有锁定的打开文件(尤其是打开的会话)。

参见

这些函数与 反引号运算符 密切相关。

目录

  • escapeshellarg — 将字符串转义为 shell 参数
  • escapeshellcmd — 转义 shell 元字符
  • exec — 执行外部程序
  • passthru — 执行外部程序并显示原始输出
  • proc_close — 关闭由 proc_open 打开的进程并返回该进程的退出代码
  • proc_get_status — 获取由 proc_open 打开的进程的信息
  • proc_nice — 更改当前进程的优先级
  • proc_open — 执行命令并打开输入/输出的文件指针
  • proc_terminate — 杀死由 proc_open 打开的进程
  • shell_exec — 通过 shell 执行命令并返回完整的输出作为字符串
  • system — 执行外部程序并显示输出
添加备注

用户贡献的备注 33 个备注

9
valqk at lozenetz dot org
18 年前
如果您将 php chroot 到没有 /bin/sh 的环境中,您将无法执行任何命令!即使您调用
mail(),它会调用 sendmail ... 实际上 sendmail 从未被调用,因为 /bin/sh 不在 chroot 中!
所以结论是:您必须有 /bin/sh 才能执行某些操作!!!
非常重要!
我在找到这个的过程中浪费了好几天,希望它能帮到其他人!!!
2
sam at freepeers dot com
19 年前
为了更清楚地说明在最后几篇文章中所说的内容

"exec"、"反引号"、"system" 等等在 Windows 2003 上默认情况下将失败。

您必须修改 cmd.exe 的安全性,以授予 IUSR-computername 用户帐户必要的权限,至少是读写权限。
1
onkelfilemon at gmail dot com
3 年前
请注意,`popen` 也是一个程序执行函数,出于某种原因,它未在此处列出。
1
jpgiot at ifrance.com
21 年前
针对 WINDOWS 用户

我查看了启动命令。实际上它非常有用。

这是我启动特定 Apache SSL 服务器的方式

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

/D 指定应用程序启动的路径(相当于 cd 到路径)
/B 无需控制台窗口启动应用程序

因此,要了解 start 的确切参数,您可以使用

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

您将在运行脚本的同一位置的名为“start.txt”的文件中获得 start 的帮助

对于 WIN 98,您可能需要稍微修改您的命令

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

(取自另一篇文章)
2
not at any dot com
18 年前
终于!坚持就是胜利,几天都在尝试各种方法!

我不想使用批处理文件。我试图使用 PHP 来摆脱批处理文件。

我不想调用一个文件来解析参数以调用一个 shell 来调用一个文件。我现在有“系统”,其中批处理文件分层三层和五层。

我只是想运行一些东西。

CALL,在 WinXP 上测试,马上将在更多操作系统上测试,在 PHP4 和 5 中,使用 exec、system、popen 和 passthru 都可以。

这是我简陋的示例函数。

// 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";

// 以下所有方法在 Win XP Pro 上都可以运行
passthru ($shellcommand);
exec ($shellcommand);
system ($shellcommand);
shell_exec ($shellcommand);
$proc= popen ($shellcommand, "r"); //$proc 包含输出

在 WINDOWS 上带空格的超长路径名!

所有这些都在一个长长的连接的命令行中,包含多个带引号的文件名参数

shell 脚本的乐趣!
1
leaetherstrip at inbox dot ru
20 年前
关于 XP 用户的说明:XP 家庭版不允许直接设置文件和文件夹的权限。您应该使用 cacls 命令行实用程序来执行此操作。

例如

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

使 IIS 用户对 cmd.exe 拥有完全访问权限(潜在的安全漏洞!),因此 PHP 可以派生并执行外部程序。
1
dotpointer
20 年前
Win32 / PHP 4.3.6...

如果您计划在服务器上启动显示消息框(需要服务器端确认)的程序,或者让它们保持运行(例如 notepad.exe),并且 exec 命令似乎陷入死循环,那么您的程序可能已经启动了,但您看不见。因为 Web 服务器作为系统进程运行,并且不允许它与桌面交互。

为了解决部分问题(查看您执行的程序),在 Windows 的控制面板中,转到管理 -> 服务,右键单击服务器服务,转到属性,在第二个选项卡(登录?)上,选中允许服务与桌面交互的框。单击确定。重启 Web 服务器,并确保确实重启了(即在任务管理器中查看服务是否关闭),否则桌面选项将不会生效。

下一步是阻止 PHP 等待进程完成(这是导致 PHP“循环”的原因)。我通过创建一个小的 Delphi 应用程序来解决这个问题,该应用程序获取我想执行的文件的路径,并通过 WinExec API 执行它,该 API 只启动子程序,但不等待它完成 = 程序完成,PHP.exe 完成脚本。问题解决!

Delphi 代码片段
WinExec(PChar(<CMD>),SW_SHOW); // 将 <CMD> 替换为程序路径。
0
匿名
16 年前
我在此页面上发现了这条评论

[引用开始]
尝试使用以下代码,结果很糟糕,出现了各种结果:例如“无法派生”、“拒绝访问”、“结果为空”,具体取决于我使用的设置,... 即使相同的代码在服务器本身的命令行中运行正常。

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

我相信,除了 nslookup 之外,这适用于大多数来自 \system32\ 目录的程序。

我必须学习以下方法,它终于可以运行了
$retstr = exec('c:\php\safedir\nslookup -type=mx myhost.com', $retarr);

... 但前提是下面列出的条件
1:将 nslookup.exe 放置(复制)到 \php\safedir\ 目录中
2:将 \php\safedir\ 目录包含在系统 PATH 环境变量中
3:将 cmd.exe 文件放置在 \php\ 中,如上面的其他注释所述
4:在 php.ini 设置中设置目录“c:\php\safedir\”
safe_mode_exec_dir = "c:\php\safedir\"
.. 也许在 php-activescript.ini 中设置,具体取决于您的系统设置。
5:使用完整路径引用 nslookup,否则将调用来自 \windows\system32\ 的文件。由于缺少权限,这对我的结果为空!

希望这对某人有所帮助,让他们省去一些时间和麻烦。
[引用结束]

这太复杂了。只需要两件事
1. IUSR 帐户对 C:\Windows\System32 目录中的 cmd.exe 具有读写权限
2. IUSR 帐户对所需的命令具有读写权限(例如,C:\Widnows\System23 目录中的 nslookup.exe)

有了这两项条件,exec 就可以正常运行了

(适用于在 Windows 平台上运行的 IIS 服务器)
0
mosesdinakaran at yahoo dot co dot in
16 年前
您好

我在执行 exec()、shell_exec() 时遇到了问题(PHP 并未在安全模式下运行)。

经过一番查找后,我发现问题出在我的系统中启用了 SELinux。

您可以通过查看日志 /var/log/messages 来确认这一点
所以我禁用了 SELinux,现在一切都正常了。

临时禁用 selinux #> setenforce 0;

虽然我认为这不是一个好主意,但我还是浏览了一些网站,找到了一个我认为不错的解决方案。

Fedora 的 SELinux 策略有一些布尔值 - 让我们看看它对我们的 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

从上面的信息中我们可以确定,由于这个 httpd_ssi_exec -- off 设置,exec() 无法正常工作。
所以我把它打开了。

#> setsebool -P httpd_ssi_exec 1;

现在我能够看到 shell_exec('ls -al') 的输出。

摩西
0
luko post cz
16 年前
致兰斯洛特

在 Windows 上,简单的 exec($my_cmd) 会执行 'cmd /c $my_cmd'
如果 $my_cmd 中有空格,则需要用双引号将其括起来
cmd /c "$app $target" 会起作用

此外,如果 $app 和 $target 中有空格,它们也需要用双引号括起来
cmd /c ""$app" "$target""

因此,将你的 $cmd 包含在另外两个双引号中,并且不要忘记转义斜杠 \\

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

然后 exec($cmd) 就会起作用 :)
不再需要 chdir 了...
0
jakster at gmx dot net
16 年前
为了创建子进程,我使用以下代码

<?php
fclose
(STDOUT); //关闭所有输出,否则将无法运行
fclose(STDIN);
fclose(STDERR);

if(
pcntl_fork()) {
exit;
//返回到调用者
}

//在后台运行的代码

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

?>

我从我的网站上调用这个脚本,使用以下代码
<?php
function fork($script){ //运行一个相对于文档根目录的 fork 后的 php 脚本。不会显示任何输出!
global $config;
$cmd = "/usr/bin/php \"" . dirname($_SERVER['SCRIPT_FILENAME']) . "/includes/forked/forkHelper.php\" \"" . $script . "\"";
exec($cmd);
}
?>
0
steve dot robinson at frogneck dot com
17 年前
如果你想使用 exec 运行一个 CGI 并通过一个 php 文件输出内容,则需要将头部信息与内容分开,并分别输出。

此外,至少在我的尝试执行的 CGI 中,缺少换行符,导致一些 JavaScript 无法正常工作,因此你可能需要将换行符添加回结果输出中。这是我用于正确输出 CGI 的代码...

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

//获取传递给 CGI 的参数..
putenv('QUERY_STRING=' . $_SERVER['QUERY_STRING']);

//当遇到空行 ('') 时,你将知道你已超出头部信息
//
$inheader=true;
foreach(
$output as $val){
if(
$val=='')
$inheader=false;
if(
$inheader)
header($val);
else
echo(
$val . "\n"); //输出内容
}
?>
0
php at fendy dot org
17 年前
使用 schtasks.exe 安排 WinXP 任务,并使用 PHP 执行命令,有时可能无法正常工作。

这是因为,Apache 在放置调度时,没有权限访问某些系统文件。我的做法是:创建一个普通用户帐户,并将 Apache 服务分配给该帐户登录。

在“运行”窗口中打开“services.msc”,在列表中查找 Apache,右键单击并进入“属性”。单击第二个选项卡“登录”,然后填写“此帐户”字段。

当然,Apache 需要在首次设置时作为服务安装。

希望这能帮到大家。

Fendy Ahmad
0
Anonymous
17 年前
在我看来,最好的方法是将 cmd.exe 复制到 web 目录下的某个安全目录中,将其添加到 Windows 路径中,然后使用系统命令从那里调用它。这样似乎可以绕过任何安全漏洞。
0
Matt-kun
17 年前
只是一个简单的说明,可以帮助人们摆脱一些头痛。

在使用
<?
$filepath = "the path of the file";
exec("program -command $filepath ");
fopen($filepath,rw);
?>

请确保对 Linux\unix 路径使用 "\ "(\ 空格),对 fopen 使用 " " 空格。这都是一些非常基本的东西,你通常不会认为它们会导致问题,但当你尝试将斜杠传递给 fopen 时,它要么崩溃,要么更糟糕的是,工作不正常 =D。反之亦然,对于任何使用 "\ " 来表示文件路径/名称中的空格的程序来说也是如此。

我在使用 <? exec(" cp $path "); ?> 和 <? fopen("$path"); ?> 时遇到了这个问题。为了解决这个问题,我使用了 str_replace(" ","\ ",$path); 和 str_replace("\ ", " ",$path);

*注意,这只是很多伪代码,有更快、更高效的方法来执行相同的操作,但我认为这可能有助于那些对文件路径感到困惑的人 =D。
0
judas dot iscariote at gmail dot com
18 年前
这些函数通常被认为是有害的,如果没有适当的输入验证程序,就像 eval() 一样糟糕。

如果你想做的事情可以通过其他机制实现,**就用那种方法,即使它需要更多时间**。

如果你的服务器因为代码中缺少 escapeshell*** 而被“入侵”,不要哭泣或责怪 PHP,你已经收到警告了。
0
manokan at manokan dot net
18 年前
关于“无法创建子进程”错误的更多信息。

这让我抓狂!我检查了 IUSR_[服务器] 帐户是否有读取和执行 cmd.exe 的权限。但它仍然失败。直到我快要绝望了,我才偶然发现“特殊权限”。(单击常规权限列表下的高级选项卡。)在那里我发现,不知何故,IUSR_[服务器] 帐户有一个特殊权限,**拒绝**访问!当然,拒绝会覆盖其他所有内容。

这是一个新安装的 XP pro。这应该是某种默认设置(我猜是 IIS)来设置此拒绝权限,只是为了让我们痛苦不堪。
0
abhilashp at clariontechnologies dot co dot in
18 年前
我在 FreeBSD 服务器上使用 PHP 4.4.0,遇到了将 shell 脚本作为后台进程运行的问题,使用了 exec() 和 system() 命令。

我尝试了上面提到的所有方法,但没有成功,然后我编写了这个脚本,并确定它将在所有 Linux 版本上运行...看看它是否对大家有帮助...

我把我的 shell 脚本放在变量 $ExecCommand 中

并使用了 proc_close 和 proc_open 函数,代码如下

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

在上面的代码行之后,其余的普通 php 脚本继续执行....

希望它对大家有帮助..
0
margus at kohv dot com
19 年前
嗯,当我想从 PHP 中启动一个无限运行的 PERL 脚本时,我遇到了这个问题。不知何故,我无法让 PHP 脚本在执行 PERL 脚本后返回。所以最后我找到了以下解决方案

PHP 文件
-------------------
<?php
exec
("perl /home/chatserver.pl > /dev/null");
?>
-------------------
此脚本将通过 HTTP 运行。

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

# 这里是一些正常的代码...
-------------------

希望它能帮到某人 :)
Margus
0
sean @T keenio - dot - com
19 年前
为了澄清,后台 shell exec()ing 与 Unix 下的 fork() 不同。如果 PHP 支持像 Perl 和其他脚本语言那样的 fork(),那就太好了。简单地 exec() 一个进程并将其发送到后台并不相同。

真正的 fork() 会复制当前环境,并复制正在运行的脚本,从而产生两个实例,一个子进程,一个父进程。子进程和父进程可以确定它们是哪个副本,然后根据此做出不同的执行路径选择。通常,一个副本会执行一些“繁忙工作”,而另一个则返回正常执行。但无论如何,这两个函数都存在于同一个代码中,而不是一个单独的外部程序中。exec()ing 无法为你做到这一点。
0
vosechu at roman-fleuve dot com
20 年前
一个帮助我很多(每个命令的最佳(+)/最差(o))以及何时使用每个命令(w)的快速图表。

| exec(string cmd, [array cmd_output, [int cmd_exit_status]])
+- 第二个(可选)参数保存一个包含输出的数组,逐行排列。
+- 第三个(可选)参数保存已执行程序的退出状态。
w- 当命令的输出仅对程序重要时。

| system(string cmd, [int cmd_exit_status])
+- 将 ASCII 输出直接回显到浏览器(仅限 stdout;stderr 必须通过在命令后面添加 2>&1 来重定向,以便查看错误)。
+- 第二个(可选)参数保存已执行程序的退出状态。
w- 当命令的输出对用户重要时。

我越回顾我的笔记,就越不关心最后两个函数。
Shell_exec() = exec() + implode() - 退出代码。
虽然需要能够通过 php 传输二进制文件,但大多数人永远不会使用 passthru

| passthru(string cmd, [int cmd_exit_status])
+- 将二进制输出直接回显到浏览器窗口。
+- 第二个(可选)参数保存已执行程序的退出状态。
w- 当命令的输出是二进制文件时。

| shell_exec(string cmd) <-- 最小的功能,以保持与正常使用反引号的同步。
+- 返回完整输出作为字符串,而不是直接返回到浏览器(仅限标准输出;标准错误必须重定向)。
o- 无法检查退出状态(应使用 system(),将标准错误和标准输出都重定向到 /dev/null 以获取退出代码)。
0
ferchland at computer-kontor dot de
20 年前
我尝试在 WinNT、Apache 2、PHP4 上派生一个 GUI 进程。
我在任务管理器进程列表中看到了新进程(notepad.exe),但没有看到任何记事本窗口!
在服务->Apache 中激活“允许与桌面交互”复选框后,一切正常,只需一个简单的命令
exec("start c:\\winnt\\notepad.exe");
0
dens at dodgeball dot com
20 年前
昨晚我卡了一个半小时,试图让 Perl 在运行 exec() 命令后将值传回我的 PHP 脚本。

由于我的 Perl 脚本使用的是 STDOUT(在被传递命令行变量后),我预期我的 .pl 脚本中使用的变量可以在 PHP 中访问,毫无疑问。

当然,这不起作用,最后我在朋友(肖恩 = 超级明星)的帮助下解决了:你需要在 exec() 命令中使用 echo 来将值返回到 PHP。

由于我返回了多个值,我在我的 .pl 脚本中添加了管道分隔符,然后使用 PHP 解析字符串以将我的数据检索到不同的变量中。

看看吧

# 使用数据访问 .pl 脚本
$mydata = exec("script.pl 'command line args' ");
exec("exit(0)");

# 解析从 .pl 脚本返回的值
list($strA, $strB) = split ('[|]', $mydata);
echo "valueA: " . $strA."<br>";
echo "valueB: " . $strB."<br>";

哇哦!
/d
0
software at yvanrodrigues dot com
21 年前
关于 Windows 中无法派生的消息的更多信息

我想确认这个问题与 %SYSTEMROOT%\SYSTEM32 的权限有关。用户(通常是匿名登录)必须对 cmd.exe 具有执行权限

这与大多数其他编程语言不同。例如,在 C 中,spawn 和 exec 函数不会尝试打开 shell,它们直接创建新进程。PHP 通过 cmd.exe(或 command.com)创建新进程,就像 C 的 system() 函数一样。这对那些试图运行批处理文件的人来说很好,但这对于运行其他 .exe 文件来说效率非常低。

我对提升 system32 目录中的权限感到不安,但你可以通过将 cmd.exe 复制到你的 PHP 目录来解决这个问题。Windows 会首先在那里查找,如果找不到,它会检查路径。注意:我指的是 php.exe 所在的目录,而不是你的脚本目录。

我已经通过在尝试执行脚本时运行 filemon.exe 来确认了这一点,你可以看到它试图启动 cmd.exe 进程。
0
qscripts at lycos dot nl
21 年前
为什么不使用每个版本的 Windows 都提供的“start”实用程序在 Windows 计算机上后台启动进程?例如

exec("start song.mp3");

这将导致 .MP3 文件类型的默认处理应用程序开始播放选定的歌曲。
0
kop at meme dot com
22 年前
AFICT,标准的 Unix Apache 配置在后台运行作业时会导致一个罕见的问题。MaxRequestsPerChild 指令导致子进程在 1000 个请求后终止,任何与子进程相关的后台进程都将随着子进程的终止而死亡,除非它们使用“nohup”命令启动。因此,在后台启动作业的正确方法是使用

exec('nohup my-command > /dev/null 2>&1 &')
0
ramirosuarez at fibertel dot com dot ar
22 年前
适用于 Windows 用户

请记住,许多无法派生的错误是由于权限不足造成的。

CMD.EXE、TEMP 目录(或你在 php.ini 中指定的任何目录)以及你用于上传或操作文件的目录都需要具有写权限?通常是用户 USER。

这将对所有使用 GD 库或其他操纵图形图像的程序的人很有用。
0
GCMXZPJPDJER at spammotel dot com
22 年前
要从 php 中在后台执行脚本,你不需要使用 mikehup 或其他工具。只需执行

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

mat
0
daniel dot hopp at godot dot de
22 年前
Re: session_write_close()

要在会话中启动后台进程,我建议
使用启动-停止守护进程并通过 ENV 传递参数。

示例
----------------------------------------
<?php
// 在会话中..
exec("/some/where/launch.sh 300");
// ..立即完成。
?>

----------------------------------------
#!/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);

----------------------------------------
-1
manokan at manokan dot net
18 年前
让我们更清楚地说明一下 exec() 中的“无法派生”错误。

默认情况下,Windows XP 将临时 Internet 用户帐户(IUSER-[计算机名])对 cmd.exe 的所有权限设置为拒绝。这会覆盖所有内容。

你必须修改 cmd.exe 的安全性,至少为 IUSER-计算机名帐户授予读写执行权限,并删除拒绝权限。
-1
Shaun
19 年前
试图使用“exec”在 Win2K3 上(据我所知,这也会发生在 Win2K 上)从运行在 IIS 上的 PHP 脚本中运行辅助可执行文件,无法调用可执行文件。

在 Win2K 上使用 Apache 提供页面调用相同辅助可执行文件的相同 PHP 脚本运行成功。

解决方案:在 Win2K3(可能还有 Win2K)上,为 IIS IUSR_xxxxx 来宾用户授予 Windows 根目录下的 System32 文件夹中 Cmd.exe 的读取和执行权限。

这让我困惑的时间比预期的要长!希望这能帮助其他人避免同样的命运!
-1
kristof_jebens at hotmail dot com
21 年前
对于运行 Apache 1.3.22 的 WIN2K Server 用户,如果无法运行可执行文件...

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

这对我来说是唯一奏效的方法。
希望这有帮助
-1
deschampsbest at noos dot fr
22 年前
我需要知道一组使用 system 调用启动的后台任务何时终止。
我找不到要调用的函数,所以我创建了一个小函数。

它基本上循环检查由 ps 命令返回的结果中是否存在一个字符串。

我所有的在后台运行的命令都包含由 posix_getpid 返回的 pid。

我能够启动许多后台任务,并有效地等待它们全部完成。

在此之前,我基本上会休眠 N 秒。

如果有已知的或更好的方法,我表示歉意。

谢谢,
新蜂
===============
===============

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