如果您将 php chroot 到没有 /bin/sh 的环境中,则无法执行任何命令!即使您调用
mail() 并调用 sendmail ... 实际上 sendmail 从未被调用,因为 /bin/sh 不在 chroot 中!
所以总之:您必须拥有 /bin/sh 才能执行某些操作!!!
非常重要!
我在找到这个的过程中浪费了几天时间,希望它能帮助到其他人!!!
在后台执行程序之前,应该关闭带有锁定的打开文件(特别是打开的会话)。
这些函数也与反引号运算符密切相关。
如果您将 php chroot 到没有 /bin/sh 的环境中,则无法执行任何命令!即使您调用
mail() 并调用 sendmail ... 实际上 sendmail 从未被调用,因为 /bin/sh 不在 chroot 中!
所以总之:您必须拥有 /bin/sh 才能执行某些操作!!!
非常重要!
我在找到这个的过程中浪费了几天时间,希望它能帮助到其他人!!!
为了更清楚地说明前几篇文章中所说的内容
"exec"、"反引号"、"system" 等在 Windows 2003 中默认情况下将失败。
您必须修改 cmd.exe 的安全设置,以便为用户帐户 IUSR-计算机名授予必要的权限,这些权限至少为读取和执行。
适用于 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");
(取自另一篇文章)
终于!坚持不懈得到了回报,几天来尝试了各种方法!
我不想使用批处理文件。我试图使用 PHP 来摆脱批处理文件。
我不想调用一个文件来解析参数以调用一个 shell 来调用一个文件。我现在有“系统”带有三层和五层深度的批处理。
我只是想运行一些东西。
CALL,在 WinXP 上测试,将立即在更多操作系统上测试,在 PHP4 和 5 中,使用 exec、system,适用于 popen 和 passthru。
这是我拙劣的示例函数。
// 创建 Zip
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 脚本的快乐!
关于 XP 用户的注释:XP-Home 版本不允许直接在文件和文件夹上设置权限。您应该使用 cacls 命令行实用程序来执行此操作。
例如
cacls c:\windows\system32\cmd.exe /E /G IUSR_ADMIN2003:F
为 IIS 用户提供对 cmd.exe 的完全访问权限(潜在的安全漏洞!),因此 PHP 可以派生并执行外部程序。
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> 替换为程序路径。
我在此页面上找到了以下评论
[引用开始]
尝试使用以下代码严重失败,并出现各种结果:例如“无法派生”、“访问被拒绝”、“结果为空”,具体取决于我使用的设置……即使相同的代码在服务器本身上从命令行运行。
$retstr = exec('nslookup -type=mx myhost.com', $retarr);
我认为这将适用于 \system32\ 目录中的大多数程序,而不是 nslookup。
我必须学习以下内容最终有效
$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 服务器)
你好
我在执行 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
从上面我们可以确定 exec() 不工作是因为这个 httpd_ssi_exec -- off 设置。
所以我把它打开。
#> setsebool -P httpd_ssi_exec 1;
现在我可以看到 shell_exec('ls -al') 的输出了。
Moses
致 Lancelot
很简单,在 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 了…
要派生一个进程,我使用以下代码
<?php
fclose(STDOUT); //关闭所有输出,否则将不起作用
fclose(STDIN);
fclose(STDERR);
if(pcntl_fork()) {
exit; //返回调用方
}
//在后台运行的代码
pcntl_exec("/usr/bin/php",Array($_SERVER['argv'][1]));
?>
我从我的网站上使用以下代码调用此脚本
<?php
function fork($script){ //运行相对于文档根目录的分支 PHP 脚本。不显示任何输出!
global $config;
$cmd = "/usr/bin/php \"" . dirname($_SERVER['SCRIPT_FILENAME']) . "/includes/forked/forkHelper.php\" \"" . $script . "\"";
exec($cmd);
}
?>
如果您尝试使用 exec 运行 cgi 并通过 php 文件输出内容,则需要将标头与内容分开并分别输出。
此外,至少在我的尝试执行的 cgi 的情况下,缺少换行符,导致某些 javascript 无法正常工作,因此您可能需要将换行符添加回结果输出中。这是我用来正确输出 cgi 的代码…
<?PHP
putenv('REQUEST_METHOD=GET');
//获取传递给 cgi 的参数..
putenv('QUERY_STRING=' . $_SERVER['QUERY_STRING']);
//当您遇到空行('')时,您将知道您已越过标头
//hit a blank line ('')
$inheader=true;
foreach($output as $val){
if($val=='')
$inheader=false;
if($inheader)
header($val);
else
echo($val . "\n"); //输出内容
}
?>
使用 schtasks.exe 安排 WinXP 任务并使用 PHP 执行命令有时可能会失败。
这是因为,Apache 在放置调度时没有权限访问某些系统文件。我的做法是:创建一个普通用户帐户,并将 Apache 服务分配给以该帐户登录。
在“运行”窗口中打开“services.msc”,在列表中查找 Apache,右键单击并转到“属性”。单击第二个选项卡“登录”,然后填写“此帐户”字段。
当然,Apache 需要在首次安装时作为服务安装。
希望这对任何人都有所帮助。
Fendy Ahmad
只是一个简单的提示,帮助人们解决一些头痛问题。
使用
<?
$filepath = "文件的路径";
exec("program -command $filepath ");
fopen($filepath,rw);
?>
确保您对 Linux/unix 路径使用“\ ”(\ 空格),对 fopen 使用“ ”空格。这些都是非常基本的事情,您通常不会认为会导致问题,但是当您尝试将斜杠传递给 fopen 时,它要么中断,要么更糟糕的是工作不正确 =D。反之亦然,对于任何使用“\ ”表示文件路径/名称中空格的程序。
我在使用 <? exec(" cp $path "); ?> 和 <? fopen("$path"); ?> 时遇到了此问题。为了解决它,我使用了 str_replace(" ","\ ",$path); 和 str_replace("\ ", " ",$path);
*注意,这有很多伪代码,并且有更快、更有效的方法来执行相同的操作,但我认为这可能会帮助那些对文件路径感到疯狂的人 =D。
这些函数通常被认为是有害的,如果没有适当的输入验证过程,它们和 eval() 一样糟糕。
如果您尝试执行的操作可以使用其他机制完成,** 请使用该方法,即使它需要更多时间 **。
如果您的服务器由于代码中缺少 escapeshell*** 而被“入侵”,请不要哭泣或责怪 PHP,您已被警告。
关于“无法派生”错误的更多信息。
它让我抓狂!我确实检查了 IUSR_[server] 帐户是否已设置读取和执行 cmd.exe 的权限。但它仍然失败了。直到我绝望了,才偶然发现了“特殊权限”。(单击常规权限列表下方的“高级”选项卡。)在那里我发现 IUSR_[server] 帐户不知何故拥有一个拒绝访问的特殊权限!当然,拒绝会覆盖其他所有内容。
这是新安装的 XP pro。它一定是某些内容(我猜是 IIS)的默认设置,以便设置此拒绝权限,只是为了让我们痛苦不堪。
我在 FreeBSD 服务器(PHP 4.4.0)上使用 exec() 和 system() 命令将 shell 脚本作为后台进程时遇到了问题。
我尝试了上面提到的所有方法,但都没有成功,然后我编写了这个脚本,并且确定它可以在所有 Linux 版本上运行…看看它是否对你们所有人都有帮助…
我把我的 Shell 脚本放在变量 $ExecCommand 中。
并使用了 proc_close 和 proc_open 函数,代码如下:
proc_close (proc_open ($ExecCommand,array(),$somefun));
在上面这行代码之后,其余的普通 php 脚本继续执行…
希望它对你们有所帮助。
嗯,当我想从 PHP 启动一个无限运行的 PERL 脚本时,遇到了这个问题。不知何故,我无法让 PHP 脚本在执行 PERL 脚本后返回。所以最终我找到了以下解决方案
PHP 文件
-------------------
<?php
exec("perl /home/chatserver.pl > /dev/null");
?>
-------------------
此脚本将通过 HTTP 运行。
PERL 文件
-------------------
#!/usr/bin/perl
fork 并退出 1;
# 这里是一般的代码...
-------------------
希望它能帮助到某些人 :)
Margus
澄清一下,后台 shell exec() 与 Unix 下的 fork() 不同。如果 PHP 像 Perl 和其他脚本语言一样支持 fork() 则会很有用。简单地 exec() 一个进程并将其发送到后台并不相同。
真正的 fork() 会复制当前环境并复制正在运行的脚本,以便有两个实例,一个子进程,一个父进程。子进程和父进程可以确定它们是哪个副本,然后根据该副本采取不同的执行路径。通常,一个副本会执行一些“繁忙工作”,而另一个副本则返回到正常的执行。但无论如何,这两个函数都存在于同一代码中,而不是一个单独的外部程序。exec() 无法为您做到这一点。
一个快速图表,对我帮助很大(每个命令的最佳 (+) / 最差 (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) <-- 最小功能以保持与正常使用反引号的同步。
+- 将完整输出作为字符串返回,而不是直接返回到浏览器(仅 stdout;stderr 必须重定向)。
o- 无法检查退出状态(应使用 system() 将 stderr 和 stdout 都重定向到 /dev/null 以获取退出代码)。
我尝试在 WinNT、Apache 2、PHP4 上派生一个 GUI 进程。
我在任务管理器进程列表中看到了新进程(notepad.exe),但任何地方都没有记事本窗口!
在服务 -> Apache 中激活“允许与桌面交互”复选框后,一切都可以使用简单的命令工作
exec("start c:\\winnt\\notepad.exe");
昨晚我花了大约一个半小时的时间试图让 Perl 在运行 exec() 命令后将值传回我的 PHP 脚本。
由于我的 Perl 脚本正在使用 STDOUT(在传递命令行变量后),我预计在我的 .pl 脚本中使用的变量可以在 PHP 中访问,无需任何疑问。
当然,这不起作用,我最终在朋友的帮助下(Shawn = 超级明星)解决了这个问题:您需要回显 exec() 命令才能将值返回到 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
关于 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 进程。
为什么不使用 Windows 每个版本都提供的“start”实用程序在 Windows 计算机上后台启动进程?例如
exec("start song.mp3");
这将导致 .MP3 文件类型的默认处理应用程序开始播放选定的歌曲。
据我所知,标准的 Unix Apache 配置在后台运行作业时会导致一个罕见的问题。MaxRequestsPerChild 指令会导致子进程在 1000 个请求后终止,与子进程关联的任何后台进程都将与子进程一起死亡,除非它们是使用“nohup”命令启动的。因此,在后台启动作业的正确方法是使用
exec('nohup my-command > /dev/null 2>&1 &')
适用于 Windows 用户
请记住,许多“无法派生”错误是由于权限不足造成的。
CMD.EXE、TEMP 目录(或您在 php.ini 中指定的任何目录)以及您用于上传或操作文件的目录都需要具有写入权限?通常是用户 USER。
这将对所有使用 GD 库或其他操纵图形图像的程序的人员很有用。
要从 php 后台执行脚本,您不需要使用 mikehup 或其他工具。只需执行
`/usr/bin/php -q foobar.php >/dev/null 2>&1 &`;
mat
关于: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);
----------------------------------------
让我们更清楚地说明一下,关于 exec() 中的“无法派生”错误。
默认情况下,Windows XP 将临时 Internet 用户帐户 (IUSER-[computername]) 的 cmd.exe 的所有权限设置为拒绝。这会覆盖所有内容。
您必须修改 cmd.exe 的安全设置,至少为 IUSER-computername 帐户授予读取和执行权限,并删除拒绝权限。
尝试使用“exec”在 Win2K3(据说这也会在 Win2K 上发生)上运行辅助可执行文件,该可执行文件来自 IIS 上运行的 PHP 脚本,但未能调用可执行文件。
在使用 Apache 提供服务的 Win2K 上运行相同的 PHP 脚本,调用相同的辅助可执行文件,则可以正常工作。
解决方案:在 Win2K3(以及可能在 Win2K 上),为 IIS IUSR_xxxxx 来宾用户授予对位于 Windows 根目录下的 System32 文件夹中的 Cmd.exe 的读取和执行权限。
这个困惑了我比应该的时间更长!希望这能帮助其他人免受同样的命运!
对于运行 Apache 1.3.22 的 WIN2K Server 用户,如果无法运行可执行文件...
exec('c:\\WINNT\\system32\\cmd.exe /c START c:\\file.exe');
这是唯一对我有用的方法。
希望对您有所帮助
我需要知道何时一组使用 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>");
}