我在生产服务器上使用php 5.2.9,似乎exec()函数表现为"非标准".
如果我运行,exec("ls", $output, $return_var)
那么$output
将按预期包含当前文件夹中的文件列表,但$return_var
将按预期设置为-1而不是0.我正在使用它$return_var
来确定命令在哪里成功完成,并在测试的每个其他服务器上按预期工作:)
有没有人遇到过这样的情况?
编辑:
<?php
$command = "asd";
$t1 = time();
$output = Array();
$result = -5;
$r = exec($command, $output, $result);
$t2 = time();
echo "<pre>";
var_export(Array(
'command'=>$command,
'result'=>$result,
'output'=>implode("\n", $output),
'r'=>$r,
't2-t1'=>$t2-$t1,
));
echo "</pre>";
Run Code Online (Sandbox Code Playgroud)
无论我输入什么命令$command
,$result
总是-1,即使对于不存在的命令......这很奇怪
假设返回 $result == -1 的系统是基于 Unix 的(我不知道使用相同代码的 Windows 会如何表现)
PHP (5.2.9) exec() 函数不会调用 C exec() 原语(如果无法替换/执行进程,则返回 -1,但此处情况并非如此)。相反,它调用 popen() 创建管道,执行 fork() 并使用您的命令执行 shell。return_value -1 不是 C 原语的直接结果,而是由 PHP 内部构建的,具体取决于命令的处理方式。换句话说,“ls”命令可能已经执行得很好,但例如 PHP 无法正确关闭管道。
查看 ext/standard/exec.c 中的 C 代码,返回码为 -1 的原因可能有两个,由错误触发;第二个发生在 popen() 调用之后
fp = VCWD_POPEN(cmd_p, "r");
if (!fp) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to fork [%s]", cmd);
goto err;
}
// ...
err:
pclose_return = -1;
goto done;
Run Code Online (Sandbox Code Playgroud)
但是在这种情况下,您将看不到结果,并且日志将显示错误。
稍后,通过以下行设置 return_value
pclose_return = php_stream_close(stream);
Run Code Online (Sandbox Code Playgroud)
查看 _php_stream_free() (php_stream_close() 是一个被 _php_stream_free() 替换的宏),最有可能返回 -1 的候选者是
ret = stream->ops->close(stream, preserve_handle ? 0 : 1 TSRMLS_CC);
Run Code Online (Sandbox Code Playgroud)
它又间接调用 C 原语 pclose()。根据说明书
如果 wait4(2) 返回错误或检测到其他错误,则 pclose() 函数返回 -1。
关闭管道期间似乎检测到错误,但这并不妨碍设置结果数据。要严格查找原因,需要检查操作系统设置和日志、PHP配置和编译参数。
我会推荐
请注意,版本 5.3 中存在与 PHP suhosin 模块相关的更改,默认情况下增强了运行 PHP 文件时的安全性。