如果您将 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-computername 用户帐户必要的权限,至少是读写权限。
针对 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 都可以。
这是我简陋的示例函数。
// 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 脚本的乐趣!
关于 XP 用户的说明:XP 家庭版不允许直接设置文件和文件夹的权限。您应该使用 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);
我相信,除了 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 服务器)
您好
我在执行 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') 的输出。
摩西
致兰斯洛特
在 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){ //运行一个相对于文档根目录的 fork 后的 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']);
//当遇到空行 ('') 时,你将知道你已超出头部信息
//
$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
在我看来,最好的方法是将 cmd.exe 复制到 web 目录下的某个安全目录中,将其添加到 Windows 路径中,然后使用系统命令从那里调用它。这样似乎可以绕过任何安全漏洞。
只是一个简单的说明,可以帮助人们摆脱一些头痛。
在使用
<?
$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。
这些函数通常被认为是有害的,如果没有适当的输入验证程序,就像 eval() 一样糟糕。
如果你想做的事情可以通过其他机制实现,**就用那种方法,即使它需要更多时间**。
如果你的服务器因为代码中缺少 escapeshell*** 而被“入侵”,不要哭泣或责怪 PHP,你已经收到警告了。
关于“无法创建子进程”错误的更多信息。
这让我抓狂!我检查了 IUSR_[服务器] 帐户是否有读取和执行 cmd.exe 的权限。但它仍然失败。直到我快要绝望了,我才偶然发现“特殊权限”。(单击常规权限列表下的高级选项卡。)在那里我发现,不知何故,IUSR_[服务器] 帐户有一个特殊权限,**拒绝**访问!当然,拒绝会覆盖其他所有内容。
这是一个新安装的 XP pro。这应该是某种默认设置(我猜是 IIS)来设置此拒绝权限,只是为了让我们痛苦不堪。
我在 FreeBSD 服务器上使用 PHP 4.4.0,遇到了将 shell 脚本作为后台进程运行的问题,使用了 exec() 和 system() 命令。
我尝试了上面提到的所有方法,但没有成功,然后我编写了这个脚本,并确定它将在所有 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 and exit 1;
# 这里是一些正常的代码...
-------------------
希望它能帮到某人 :)
Margus
为了澄清,后台 shell exec()ing 与 Unix 下的 fork() 不同。如果 PHP 支持像 Perl 和其他脚本语言那样的 fork(),那就太好了。简单地 exec() 一个进程并将其发送到后台并不相同。
真正的 fork() 会复制当前环境,并复制正在运行的脚本,从而产生两个实例,一个子进程,一个父进程。子进程和父进程可以确定它们是哪个副本,然后根据此做出不同的执行路径选择。通常,一个副本会执行一些“繁忙工作”,而另一个则返回正常执行。但无论如何,这两个函数都存在于同一个代码中,而不是一个单独的外部程序中。exec()ing 无法为你做到这一点。
一个帮助我很多(每个命令的最佳(+)/最差(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 以获取退出代码)。
我尝试在 WinNT、Apache 2、PHP4 上派生一个 GUI 进程。
我在任务管理器进程列表中看到了新进程(notepad.exe),但没有看到任何记事本窗口!
在服务->Apache 中激活“允许与桌面交互”复选框后,一切正常,只需一个简单的命令
exec("start c:\\winnt\\notepad.exe");
昨晚我卡了一个半小时,试图让 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
关于 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 文件类型的默认处理应用程序开始播放选定的歌曲。
AFICT,标准的 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
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);
----------------------------------------
让我们更清楚地说明一下 exec() 中的“无法派生”错误。
默认情况下,Windows XP 将临时 Internet 用户帐户(IUSER-[计算机名])对 cmd.exe 的所有权限设置为拒绝。这会覆盖所有内容。
你必须修改 cmd.exe 的安全性,至少为 IUSER-计算机名帐户授予读写执行权限,并删除拒绝权限。
试图使用“exec”在 Win2K3 上(据我所知,这也会发生在 Win2K 上)从运行在 IIS 上的 PHP 脚本中运行辅助可执行文件,无法调用可执行文件。
在 Win2K 上使用 Apache 提供页面调用相同辅助可执行文件的相同 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>");
}