0

Problem: I am running java files via PHP that a user submits. It is possible for a java file to cause an infinite loop. How can I handle this in the php execution process?

Here is my code:

$proc = proc_open($javaCmd, array(array("pipe", "r"), array("pipe", "w"), array("pipe", "w")), $pipes);
// Check status here logic ?
proc_close($proc);

It currently waits for the process to finish, but I want it to timeout after 30 seconds or a minute. I tried set_time_limit(x), but that does not terminate java.exe.

My question is, is it possible for me to check the status of java.exe process after X seconds, then terminate if it is still running? Or, do I need to use a timeout functionality in java (i.e. have a main class that executes the user's submitted classes on a thread)

Community
  • 1
  • 1
Gaʀʀʏ
  • 4,372
  • 3
  • 39
  • 59

1 Answers1

2

Yes, it's possible. I don't think a java process is any different than any other process in this regard. See these links for unix exec with timeout and windows exec with timeout.

I didn't write this code, but here it is copy-pasted in case the original disappears from the Internet:

For unix:

<?php
  function PsExecute($command, $timeout = 60, $sleep = 2) {
        // First, execute the process, get the process ID

        $pid = PsExec($command);

        if( $pid === false )
            return false;

        $cur = 0;
        // Second, loop for $timeout seconds checking if process is running
        while( $cur < $timeout ) {
            sleep($sleep);
            $cur += $sleep;
            // If process is no longer running, return true;

           echo "\n ---- $cur ------ \n";

            if( !PsExists($pid) )
                return true; // Process must have exited, success!
        }

        // If process is still running after timeout, kill the process and return false
        PsKill($pid);
        return false;
    }

    function PsExec($commandJob) {

        $command = $commandJob.' > /dev/null 2>&1 & echo $!';
        exec($command ,$op);
        $pid = (int)$op[0];

        if($pid!="") return $pid;

        return false;
    }

    function PsExists($pid) {

        exec("ps ax | grep $pid 2>&1", $output);

        while( list(,$row) = each($output) ) {

                $row_array = explode(" ", $row);
                $check_pid = $row_array[0];

                if($pid == $check_pid) {
                        return true;
                }

        }

        return false;
    }

    function PsKill($pid) {
        exec("kill -9 $pid", $output);
    }

For windows:

<?php
// pstools.inc.php

    function PsExecute($command, $timeout = 60, $sleep = 2) {
        // First, execute the process, get the process ID
        $pid = PsExec($command);

        if( $pid === false )
            return false;

        $cur = 0;
        // Second, loop for $timeout seconds checking if process is running
        while( $cur < $timeout ) {
            sleep($sleep);
            $cur += $sleep;
            // If process is no longer running, return true;
            if( !PsExists($pid) )
                return true; // Process must have exited, success!
        }

        // If process is still running after timeout, kill the process and return false
        PsKill($pid);
        return false;
    }

    function PsExec($command) {
        exec( dirname(__FILE__). "\\psexec.exe -s -d $command  2>&1", $output);

        while( list(,$row) = each($output) ) {
            $found = stripos($row, 'with process ID ');
            if( $found )
                return substr($row, $found, strlen($row)-$found-strlen('with process ID ')-1); // chop off last character '.' from line
        }

        return false;
    }

    function PsExists($pid) {
        exec( dirname(__FILE__). "\\pslist.exe $pid 2>&1", $output);

        while( list(,$row) = each($output) ) {
            $found = stristr($row, "process $pid was not found");
            if( $found !== false )
                return false;
        }

        return true;
    }

    function PsKill($pid) {
        exec( dirname(__FILE__). "\\pskill.exe $pid", $output);
    }
eis
  • 51,991
  • 13
  • 150
  • 199
  • Thanks! I will try this out and post my results – Gaʀʀʏ Aug 19 '12 at 22:57
  • I copied the code exactly for windows, but it is returning false for the $pid every time. If I remove that, it runs the time of the timeout, and kills the process as expected. – Gaʀʀʏ Aug 28 '12 at 04:21
  • @le_garry I don't really understand how that can be, since if it returns false, it wouldn't have a pid to kill process with. But if it works as expected when removing, I guess that's ok, then... :) – eis Aug 28 '12 at 09:02
  • Yeah, doesn't make sense to me either, perhaps pskill has a kill-all-pstools function that is triggered, since $pid is definitely === false. – Gaʀʀʏ Aug 28 '12 at 17:55
  • if you wan't to debug as to why it is false, you'd probably want to break down PsExec() function and debug it in smaller steps - it is parsing the output depending heavily on the small details, so it is very fragile with different setups and OS versions. – eis Aug 29 '12 at 08:32