如何从php脚本运行linux命令来编译c程序

时间:2014-01-15 11:34:07

标签: php linux

我正在尝试为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”; < / p>

exec($cmd,$out,$status);

但它也没有用。返回的状态是1

最有可能是许可问题。 “whoami”没有人说。请告诉我如何将所有者从nobody更改为root或如何分配从任何人执行gcc的权限

2 个答案:

答案 0 :(得分:3)

我的回答有三个主要方面

exec函数使用不当。

看看the man pages。首先,exec函数的签名是:

string exec ( string $command [, array &$output [, int &$return_var ]] )

所以exec最多可以包含3个参数。它返回命令输出的最后一行,就像文档说得非常清楚:

  

命令结果的最后一行。如果您需要执行命令并将命令中的所有数据直接传回而没有任何干扰,请使用passthru()函数。

     

要获取已执行命令的输出,请务必设置并使用输出参数。

所以在你的情况下:

$lastLine = exec($command, $fullOutput, $status);

您正在寻找什么。如果$status else 而不是0,则您的命令不成功。那就是你应该检查以做出相应的反应 任何命令的完整输出都可以在$fullOutput中找到,作为每行数组 输出如:

all went well
except for this

$fullOutput数组中会看起来像这样:

array('all went well', 'except for this');

权限仍然可以成为一个问题。

您说权限不太可能是导致问题的原因,因为您可以从命令行运行gcc。一切都很好,但是用户在服务器上运行PHP脚本是什么? 对于Web服务器,该用户通常称为 nobody apache 或其他东西,而 用户很可能不是允许运行gcc。这是PHP运行它已经设置的任何默认shell的新实例(可能是bash),并且它是登录到该shell的PHP用户,并且是那个正在调用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-configmysql_config --cflags --libs的输出,以我最近使用的一个特定示例命名)。
基本上,你的脚本根本无法处理我想用像

这样的commind编译的东西
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 *。这意味着您必须致电escapeshellcmdescapeshellarg。两者都将禁止我传递有效的论据:

`mysql_config --libs --cflags`

其中包含反向标记,因此将被转义。

坦率地说,我很难看到这个练习的重点...而且我还有很多东西:危险编译(更不用说运行)用户提供的代码了例如,在您的机器上,不容忽视。您不能只编译代码,并在您的服务器上运行它:内存泄漏,段错误......哎呀,纯邪恶代码都在您的服务器上编译 取消选中 如果这是你的代码。真的,给自己留下很多眼泪,包括一个加载键盘或类似服务的iframe ......


回顾:

  • 总是检查男人的功能,看看你是否收到所有返回的信息
  • 检查实际执行命令的用户的权限和运行时
  • 永远不要相信网络,不要盲目地假设人们会提交有效,无害的代码供您编译。
  • 不要重新发明轮子:存在编译服务,只需转发那些(但首先请求许可)

答案 1 :(得分:0)

尝试使用此代码从PHP文件

执行c程序
<?php 
    // used to compile the c file using exec() in php
    exec('gcc helloworld.c -o helloworld', $out, $status); 
    if (0 === $status) {
        var_dump($out);
        // used to execute the c file using exec() in php
        exec('./helloworld', $out, $status);
        if (0 === $status) {
            var_dump($out);
        } else {
            echo "Command failed with status: $status";
        }
    } else {
        echo "Command failed with status: $status";
    }
?>