我正在尝试为 c 编程做一个在线评委。当用户输入 c 代码并提交时,我的表单重定向到judge.php,这是表单的操作文件。
这是我在judge.php中写的
<?php
$text=$_POST['code'];
//echo $text;
$var_str = var_export($text, true);
file_put_contents('code.c', $text);
$ans=exec('pwd');
$ans= exec('gcc code.c');
echo $ans;
?>
我已经在 $text 中捕获了用户输入并将其写入 c 文件(code.c)。到现在为止,还好。
但是
exec(gcc code.c)
不工作,不提供任何输出。我尝试了其他 linux commnads,如 pwd、date 等。它们工作正常。这可能是什么原因以及如何解决?这不是我尝试过的目录问题
exec(pwd)
并将输出与代码所在的目录相同。我试图从终端运行相同的 code.c 文件,它运行良好。因此,这也不是“许可”问题。
还有一件事,如果任何 exec() 命令无法正常工作,如何回显生成的错误消息?
从下面的答案中得到建议后,我尝试了
$cmd="gcc -std=c99 code.c -g -Wall mysql_config --libs --cflags
-o db_obj.o --pedantic";exec($cmd,$out,$status);
但它也不起作用。返回的状态为 1
很可能是权限问题。 “whoami”没有人说。请告诉如何将所有者从nobody更改为root或如何分配从nobody执行gcc的权限
最佳答案
我的回答的三个主要方面exec
使用不当功能。
看the man pages .一、exec
函数的签名是:
string exec ( string $command [, array &$output [, int &$return_var ]] )
所以exec
最多可以接受 3 个参数。它返回命令输出的最后一行,就像文档状态一样清楚:The last line from the result of the command. If you need to execute a command and have all the data from the command passed directly back without any interference, use the passthru() function.
To get the output of the executed command, be sure to set and use the output parameter.
所以在你的情况下:
$lastLine = exec($command, $fullOutput, $status);
是你要找的。如果 $status
是不是 0
,您的命令不成功。这就是您应该检查以做出相应 react 的内容。任何命令的完整输出都可以在
$fullOutput
中找到。作为逐行数组。输出如:
all went well
except for this
在 $fullOutput
中看起来像这样大批:array('all went well', 'except for this');
权限可能仍然是一个问题。您说权限不太可能是问题的原因,因为您可以运行
gcc
从命令行。一切都很好,但是什么用户在服务器上运行 PHP 脚本?在网络服务器的情况下,该用户通常被称为nobody、apache 或其他东西,并且该用户很可能是。不是 允许运行
gcc
.是 PHP 运行它设置的任何默认 shell(可能是 bash)的新实例,并且是 PHP 的用户登录到该 shell,并且是那个用户正在调用 gcc
...知道你是谁,你属于什么群体。尝试将此添加到您的脚本中:
echo 'Script is running under user: ', exec('whoami'), '<br>', PHP_EOL;
echo 'member of the following groups: ', exec('groups'), '<br>', PHP_EOL;
在你问之前:是的,那些是逗号......不需要连接,你可以将多个变量/值传递给 echo
, 用逗号分隔。它实际上更快(将其视为 C++ 的 std::cout << some_var << another_var;
)一般问题+安全
这一切都说了又做了:从 php 脚本编译 C 代码并不像您想象的那么简单。假设我要写这个:
#include <stdio.h>
#include <time.h>
int main ( void )
{
time_t t = time(NULL);
if (t%2)
{
float val = (float) t/2.0;
//do stuff with float...
}
else
{
unsigned long long val = t/2;
//do stuff with unsigned long long...
}
}
您的 gcc test.c
命令将失败,因为您未能传递参数 -std=c99
, 例如。如果我想要一个脚本来编译给定的文件,我还希望该脚本允许我选择编译代码时使用的参数
-g
, -Wall
而且,更不用说:cflags 和 libs(pkg-config
或 mysql_config --cflags --libs
的输出,以我最近使用的一个具体示例为例)。基本上,你的脚本根本无法处理我想用类似的命令编译一些东西
gcc -std=c99 code.c -g -Wall `mysql_config --libs --cflags` -o db_obj.o --pedantic
这仍然是许多编译命令的简化版本,尤其是在调试正在开发的代码时。对于稳定版本,您可能会放弃 -g
和 --pedantic
,但你明白我的意思...想想这意味着什么,允许用户传递一组 cli 参数以及代码。他们可能会传递像
-DSOME_MACRO
这样的参数。或 -O0
,这意味着它们也可能通过 -O0 && rm -Rf *
.这意味着您必须调用 escapeshellcmd
或 escapeshellarg
.两者都将禁止我传递有效的论点,即:`mysql_config --libs --cflags`
其中包含反引号,因此将被转义。坦率地说,我很难理解这个练习的意义......而且我仍然遗漏了很多:例如,在您的机器上编译(更不用说运行)用户提供的代码的危险不是被忽视。你不能只编译代码,然后在你的服务器上运行它:内存泄漏、段错误……哎呀,纯邪恶的代码都在你的服务器上编译 未选中 如果这是您拥有的代码。真的,为自己省去很多眼泪,并包含一个加载键盘或一些类似服务的 iframe...
回顾:
关于php - 如何从 php 脚本运行 linux 命令来编译 c 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21136328/