How to run a linux command to compile a c program,

2019-09-16 18:27发布

问题:

I am trying to make an online judge for c programming. When user enters the c code and submits it, my form redirects to judge.php which is the action file for the form. Here is what I have written in 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;

?>

I have captured user input in $text and wrote it to a c file(code.c). Till now, it is fine. But exec(gcc code.c) is not working and not giving any output. I tried other linux commnads like pwd, date, etc. They are working fine. What may be the reason for this and how to fix it? It is not a directory issue i tried exec(pwd) and it gave the output as the same directory in which code is present. I tried to run same code.c file from terminal and it is running fine. So, it is also not a 'permission' problem.

One more thing, how to echo the error message generated if any exec() command is not working properly?

After getting suggestion from the answer below, i tried $cmd="gcc -std=c99 code.c -g -Wall mysql_config --libs --cflags -o db_obj.o --pedantic";

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

But it is also not working. The status returned is 1

Most probably it is permission issue. "whoami" says nobody. Please tell how to change the owner from nobody to root or how to assign the permission to execute gcc from nobody

回答1:

Three main aspects to my answer

improper use of the exec function.

Look at the man pages. First, the exec function's signature is:

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

So exec can take up to 3 arguments. It returns the last line of the command's output, like the docs state quite clearly:

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.

So in your case:

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

Is what you're looking for. If $status is anything else than 0, your command was unsuccessful. That's what you should check to react accordingly.
The full output of any command can be found in $fullOutput as a line-per-line array.
Output like:

all went well
except for this

Will look like this in the $fullOutput array:

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

permissions can be an issue, still.

You say permissions aren't likely to be the cause of the problem, because you can run gcc from the command-line. All fine and dandy, but what user is running the PHP script on the server?
In the case of web-servers, that user is often called nobody, apache or something, and that user is very likely not permitted to run gcc. It's PHP that runs a new instance of whatever default shell it has set up (bash, probably), and it's PHP's user that logs in to that shell, and it's that user that is calling gcc...

Know who you are, and what groups you belong to. Try adding this to your script:

echo 'Script is running under user: ', exec('whoami'), '<br>', PHP_EOL;
echo 'member of the following groups: ', exec('groups'), '<br>', PHP_EOL;

And before you ask: yes, those are comma's... no need to concatenate, you can pass multiple variables/values to echo, separated by a comma. It's actually faster (think of it as C++'s std::cout << some_var << another_var;)

general issues + security

This all said and done: compiling C code from a php script isn't as simple as you seem to think it is. Suppose I were to write this:

#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...
    }
}

Your gcc test.c command would fail, because you failed to pass the argument -std=c99, for example.
If I wanted a script to compile a given file, I'd also expect that script to allow me to choose which arguments I compiled my code with, too -g, -Wall and, not to mention: cflags and libs (the output of pkg-config or mysql_config --cflags --libs, to name a specific example I recently used).
Basically, your script simply cannot deal with my wanting to compile something with a commind like

gcc -std=c99 code.c -g -Wall `mysql_config --libs --cflags` -o db_obj.o --pedantic

Which still is a simplified version of what many compilation commands look like, especially when debugging code under development. For stable releases, you'd probably drop -g and --pedantic, but you get my point...
Just think of what it means, allowing the user to pass a set of cli arguments, along with the code. They might pass an argument like -DSOME_MACRO or -O0, which means they might also pass -O0 && rm -Rf *. That means you'll have to call escapeshellcmd or escapeshellarg. Both of which will prohibit me from passing a valid argument, being:

`mysql_config --libs --cflags`

Which contains back-ticks, and thus will be escaped.

To be frank, I struggle to see the point of this exercise... and I'm leaving a lot out, still: the dangers of compiling (let alone running) user-provided code on your machine, for example, are not to be overlooked. You can't just compile code, and run it on your server: memory leaks, segfaults... heck, pure evil code is all getting compiled on your server unchecked if this is the code you have. Really, save yourself a lot of tears, and include an iframe that loads codepad or some similar service...


Recap:

  • always check the man for a function, see if you're getting all information it returns
  • check the permissions and runtime for the user that is actually executing the commands
  • Never trust the network, don't blindly assume people will submit valid, harmless code for you to compile.
  • Don't reinvent the wheel: compilation services exist, just forward those (but ask for permission first)


回答2:

Try this code to execute c program from PHP file

<?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";
    }
?>


标签: php linux