关于 swbrown 的评论...如果您不想显示数据,则需要使用输出缓冲区。
例如
ob_start();
passthru("<i>command</i>");
$var = ob_get_contents();
ob_end_clean(); // 使用此方法代替 ob_flush()
这将获取命令的所有输出,并退出而不向 stdout 发送任何数据。
(PHP 4, PHP 5, PHP 7, PHP 8)
passthru — 执行外部程序并显示原始输出
passthru() 函数类似于 exec() 函数,它执行 command
。当 Unix 命令的输出为二进制数据且需要直接传递回浏览器时,应使用此函数代替 exec() 或 system()。此函数的常见用法是执行诸如 pbmplus 实用程序之类的程序,这些程序可以直接输出图像流。通过将 Content-type 设置为 image/gif
,然后调用 pbmplus 程序来输出 gif,您可以创建直接输出图像的 PHP 脚本。
command
将要执行的命令。
result_code
如果存在 result_code
参数,则 Unix 命令的返回状态将放置在此处。
版本 | 说明 |
---|---|
8.0.0 | 如果 command 为空或包含空字节,passthru() 现在会抛出 ValueError。以前它会发出 E_WARNING 并返回 false 。 |
当允许用户提供的数据传递给此函数时,请使用 escapeshellarg() 或 escapeshellcmd() 来确保用户无法欺骗系统执行任意命令。
注意:
如果使用此函数启动程序,则为了让它在后台继续运行,必须将程序的输出重定向到文件或其他输出流。否则,PHP 将会挂起,直到程序执行结束。
关于 swbrown 的评论...如果您不想显示数据,则需要使用输出缓冲区。
例如
ob_start();
passthru("<i>command</i>");
$var = ob_get_contents();
ob_end_clean(); // 使用此方法代替 ob_flush()
这将获取命令的所有输出,并退出而不向 stdout 发送任何数据。
注意 Paul Giblock:该命令*是*通过 shell 运行的。
您可以在任何 Linux 系统上通过以下方法验证这一点
<?php
passthru ('echo $PATH');
?>
您将获得 PATH 环境变量的内容,而不是字符串 $PATH。
如果您在使用 passthru("docker-compose ...bash") 时遇到丢失交互式 shell 大小信息的麻烦,请尝试使用 proc_open 代替,因为某些原因,当我使用 proc_open 时,docker-compose bash 知道外部终端的大小,但是当我使用 passthru 时,它会丢失该信息。
例如,我将
<?php
passthru("docker-compose -f docker-compose.yml bash",$ret);
?>
替换为
<?php
$empty1=array();
$empty2=array();
$proc=proc_open("docker-compose -f docker-compose.yml bash",$empty1,$empty2 );
$ret = proc_close($proc);
?>
突然,docker-compose bash 就知道了我的终端大小 :)
如果您使用 passthru() 来下载文件(用于动态生成的內容或 Web 服务器根目录之外的內容),并使用类似的代码
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"myfile.zip\"");
header("Content-Length: 11111");
passthru("cat myfile.zip",$err);
并且您的下载正常进行,但后续的下载/链接点击出现故障,标题和二进制数据出现在整个网站上,请尝试在 passthrough 之后添加
exit();
这将在下载完成后退出脚本,并且不会影响任何未来的操作。
我试图实现一个允许运行具有参数的任意 CLI 命令的系统,但是我一直遇到来自命令的用户提示的问题,因为这些提示会让执行挂起。解决方案很简单:只需使用 passthru(),因为它会输出所有内容并正确处理用户提示。
请记住,使用 passthru 时,请使用完整路径(例如 '/usr/local/bin/foo' 而不是 'foo'),否则您将获得退出代码 127(未找到命令)。
PHP 的程序执行命令在处理 STDERR 时会惨败,并且 proc_open() 命令在 Windows 下的非阻塞模式下并不总是那么有效。
虽然此命令很有用,但情况并没有什么不同。要形成一种机制来查看/捕获 STDOUT 和 STDERR 输出,请将命令管道到 'tee' 命令(可以在 Windows 上找到),并将整个命令包装在输出缓冲中。
Dustin Oprea
如果您使用 chrooted apache 和 php,那么您还需要将 /bin/sh 放入 chrooted 环境中。否则,exec() 或 passthru() 将无法正常工作,并将产生错误代码 127,文件未找到。
Zak Estrada
14-Dec-2004 11:21
请记住,使用 passthru 时,请使用完整路径(例如 '/usr/local/bin/foo' 而不是 'foo'),否则您将获得退出代码 127(未找到命令)。
请记住,如果您的文件没有执行权限,您也会收到此错误。
我不知道其他人是否觉得这有用,但当我尝试在 Suse9.3 上使用 passthru() 命令时,我一直无法成功执行该命令。
$command = 'gdal_translate blahahahaha';
passthru($command);
只有在我添加以下内容后,它才正常工作:
$command = '/usr/bin/local/gdal_translate blalalala';
passthru($command);
passthru() 似乎无论你做什么都绝对要缓冲输出,即使使用 ob_implicit_flush() 也是如此。解决方案似乎是使用 popen() 代替。
文档没有提到 passthru() 只会显示标准输出,而不会显示标准错误。
如果你正在运行脚本,可以通过以下操作将 STDERR 管道到 STDOUT:
exec 2>&1
例如,以下脚本将使用 passthru() 函数实际打印一些内容...
#!/bin/sh
exec 2>&1
ulimit -t 60
cat nosuchfile.txt
我编写了一个函数,该函数从 Internet Explorer(从
注册表)获取代理服务器值。它在 Windows XP Pro 中进行了测试。
(抱歉我的英语)
<?php
function getProxyFromIE()
{
exec("reg query \"HKEY_CURRENT_USER\Software\Microsoft".
"\Windows\CurrentVersion\Internet Settings\" /v ProxyEnable",
$proxyenable,$proxyenable_status);
exec("reg query \"HKEY_CURRENT_USER\Software\Microsoft".
"\Windows\CurrentVersion\Internet Settings\" /v ProxyServer",
$proxyserver);
if($proxyenable_status!=0)
return false; #Can't access the registry! Very very bad...
else
{
$enabled=substr($proxyenable[4],-1,1);
if($enabled==0)
return false;
else
{
$proxy=ereg_replace("^[ \t]{1,10}ProxyServer\tREG_SZ[ \t]{1,20}","",
$proxyserver[4]);
if(ereg("[\=\;]",$proxy))
{
$proxy=explode(";",$proxy);
foreach($proxy as $i => $v)
{
if(ereg("http",$v))
{
$proxy=str_replace("http=","",$v);
break;
}
}
if(@!ereg("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\:".
"[0-9]{1,5}$",$proxy))
return false;
else
return $proxy;
}
else
return $proxy;
}
}
}
?>
请注意,如果在 Internet Explorer 中禁用了代理,则此函数将返回 FALSE。
此函数仅返回 HTTP 代理服务器。
用法
<?php
$proxy=getProxyFromIE();
if(!$proxy)
echo "Can't get proxy!";
else
echo $proxy;
?>
我认为记录 passthru 在 Windows 上的 Dos 中运行时似乎会抑制错误消息(在 NT 上测试)会很有用。
要显示包含错误的完整原始输出,请使用 system()。
Stuart
pasthru 函数不会通过 shell 执行程序。这意味着,除其他事项外,你的 PATH 变量从未设置。因此,你必须对所有内容使用完整路径。
我相信 system() 会在 shell 下运行你的程序。这允许程序在“正常”环境中运行。
-Paul
我在使用 exec 时遇到了问题。
我认为我们在 test.php 脚本上回显了信息。
例如:当我们尝试
exec(php test.php,$array,$error);
返回结果为 127,并且代码失败。
检查此页面上的说明给了我们一个提示,建议使用 passthru 代替。
需要注意的唯一一点是,你需要提供完整路径。
现在我们的命令变成了
passthru(/bin/php /pathtotest/test.php,$array,$error);
这有效。
耶!
PJ 的 ulimit 示例很好;但是,如果你在 ulimit 命令之后在脚本中包含多个命令,每个命令都会获得一个单独的 60 秒时间段!<br>
此外,这 60 秒是 *CPU* 时间。大多数程序挂起的原因不是 CPU 占用过高(例如,等待数据库连接),因此对于大多数用途而言,数字 60 偏高。<br>
首先尝试 "ulimit -t 1",这将在现代硬件上提供大约 10^9 个周期——足够完成很多工作!
关于僵尸问题,你可以像这样调用 bash 脚本
--------------------------
#! /bin/bash
ulimit -t 60
<your command here>
--------------------------
`command` // 反引号将你从 PHP 模式带入 shell 模式
exec('command', $output); // exec 允许你将命令的返回值作为引用捕获
shell_exec('command'); // 将输出返回给变量
system(); // 如上所述。
关于 kpierre 的帖子,请注意,如果你的 shell 脚本出错,你会在 apache 的基本 error_log 文件(而不是虚拟主机 error_log 文件)中找到它的错误输出。
如果你有时从 passthru() 中无法获得任何输出,请使用 system() 代替。这为我解决了这个问题(在使用 gcc 编译的 Tru64 Unix 上的 php 4.0.5)。
在 RH9 上的 apache 2.x 中,passthru() 每次写入 1 个字节。Apache 2.x 会为你缓冲和分块编码输出——但分块编码会将输出划分为每个 1 个字节的块...因此每个字节会有几个字节的开销。我想这种缓冲行为是设计好的——但给我使用 IE adobe acrobot 5 插件带来了问题。如果向它发送一个 1 个字节块流,插件不喜欢它——它会告诉你你的文件不是 pdf 或显示一个空白屏幕。使用输出缓冲 (ob_start / ob_endflush) 会产生合理大小的块,插件可以正常工作。