Avitar has asked for the wisdom of the Perl Monks concerning the following question:

Which is better as far as security/performance for executing another script in an exisiting one: print `"script.cgi"`; OR print system(perl "script.cgi"); OR print eval("script.cgi"); OR print exec("script.cgi"); syntax prob isn't entirely right... however i just wanted to know if there is a difference and which is the best to run on a webserver via a Perl Module.

Replies are listed 'Best First'.
Re: Executing another Script
by ikegami (Patriarch) on Aug 18, 2004 at 23:18 UTC

    ``, system, eval and exec all do different things, so it's useless to compare their performance.

    • Do you want the caller to wait for script.cgi to finish and resume execution after script.cgi is done? (yes: ``, exec)
    • Do you want the caller to resume execution immediately after script.cgi is launched, letting it run in parallel? (yes: fork+exec)
    • Do you want to capture the script.cgi's output? If you don't, it will go to STDOUT. (yes: `` and fork+exec+pipes)

    Don't use eval. You'd have to change script.cgi to play nice, but it's easier and better to write script.cgi as a proper module instead.

Re: Executing another Script
by graff (Chancellor) on Aug 19, 2004 at 02:24 UTC
    If the plan is to use the output of another script as data in the current (CGI) script (e.g. as content to be included on a web page), the three possible ways to do that are:
    # one way: my $content = `other_script`; die "No output from other_script" unless ( $content ); # another way: open( SCR, "other_script |" ) or die "other_script failed: $!"; print while (<SCR>); close SCR; # the only other way: my $tmpfile = function_returning_uniq_name(); my $status = system( "other_script > $tmpfile" ); die "other_script failed" if ( $status or -s $tmpfile == 0 ); open( TMP, $tmpfile ) or die "WTF?? can't open $tmpfile: $!"; print <TMP>; close TMP: unlink $tmpfile;
    In terms of security, I think the three methods are equivalent (I hope others will correct me if I'm wrong):

    If the name of "other_script" and any command line args that are needed are constants that you define in the source code (not derived from input CGI parameters), then there isn't much to worry about.

    If the command line needs to be constructed on the basis of CGI params, then you need to be very careful about how you do this, no matter which method you use. Ideally, CGI params would only be used (via regex matches or value comparisons) to decide which script-internal, pre-defined constants -- or which server-internal, verifiable file/directory names -- should be included in the command line. If the app is supposed to allow CGI param strings to be included on the command line, apply the tightest possible untainting.

    Regarding the 2nd, 3rd and 4th "alternatives" suggested in the OP, they won't work at all:

    • The system call returns the exit status of the command line, not the stdout content.
    • eval("script.cgi") returns the string "script.cgi"
    • exec("script.cgi") does not return to the calling script -- the named command takes the place of the calling routine in the system's process table.
    BTW, based on your proposed examples, you may need to take note: running a sub-process in a CGI script does not mean that the sub-process is "automatically" a CGI script itself -- it does not get the parameter values that the calling CGI script received, unless these are somehow (carefully) included in the command line or %ENV. You can run any command, more or less the way you would from an interactive shell on the server -- that's why you have to be careful.
      This is exactly what i was looking for. Thank you very much =)
Re: Executing another Script
by Anonymous Monk on Aug 18, 2004 at 22:57 UTC
    perldoc -f system
    system LIST system PROGRAM LIST Does exactly the same thing as "exec LIST", except that + a fork is done first, and the parent process waits for the chi +ld pro- cess to complete. Note that argument processing varies + depend- ing on the number of arguments. If there is more than +one argument in LIST, or if LIST is an array with more than + one value, starts the program given by the first element of + the list with arguments given by the rest of the list. If +there is only one scalar argument, the argument is checked for s +hell metacharacters, and if there are any, the entire argume +nt is passed to the system’s command shell for parsing (this +is "/bin/sh -c" on Unix platforms, but varies on other pla +tforms). If there are no shell metacharacters in the argument, i +t is split into words and passed directly to "execvp", which + is more efficient. Beginning with v5.6.0, Perl will attempt to flush all f +iles opened for output before any operation that may do a fo +rk, but this may not be supported on some platforms (see perlpo +rt). To be safe, you may need to set $&#9474; ($AUTOFLUSH in En +glish) or call the "autoflush()" method of "IO::Handle" on any open ha +ndles. The return value is the exit status of the program as r +eturned by the "wait" call. To get the actual exit value shift + right by eight (see below). See also "exec". This is not wh +at you want to use to capture the output from a command, for t +hat you should use merely backticks or "qx//", as described in "‘STRING‘" in perlop. Return value of -1 indicates a f +ailure to start the program (inspect $! for the reason). Like "exec", "system" allows you to lie to a program ab +out its name if you use the "system PROGRAM LIST" syntax. Agai +n, see "exec". Because "system" and backticks block "SIGINT" and "SIGQ +UIT", killing the program they’re running doesn’t actually in +terrupt your program. @args = ("command", "arg1", "arg2"); system(@args) == 0 or die "system @args failed: $?" You can check all the failure possibilities by inspecti +ng $? like this: $exit_value = $? >> 8; $signal_num = $? & 127; $dumped_core = $? & 128; or more portably by using the W*() calls of the POSIX e +xten- sion; see perlport for more information. When the arguments get executed via the system shell, r +esults and return codes will be subject to its quirks and capa +bilities. See "‘STRING‘" in perlop and "exec" for details.