Search code examples
javaphpconsoleuser-input

How to give input to java program and continue with execution using PHP?


I want to execute java programs using php code. When i write the below code, the program written in the editor is getting compiled and executed successfully.

putenv('path=C:\Program Files\Java\jdk1.8.0_73\bin');

echo shell_exec("javac $output 2>&1"); // for compiling and creating class file

echo exec("java $check 2>&1"); // for executing generated class file and prints output

Note: $output and $check variables contains required input to compile & run

But, when I try to execute java programs where we need to input some data to contine with the execution, the above code doesn't works. For example, consider the JavaScannerExample in the link: http://alvinalexander.com/java/edu/pj/pj010005

To execute the program in the link, I guess I need some interactive console to accept the input and continue with program execution. Please suggest me how to achieve this using php?

Update:

@Chris.. Tried proc_open command as suggested. See my code below:

PHP Code

<?php

$JAVA_HOME = "C:\Java\jdk1.7.0_79";
$PATH = "$JAVA_HOME\bin";
putenv("JAVA_HOME=$JAVA_HOME");
putenv("PATH=$PATH");
$result = shell_exec("javac JavaScannerExample.java 2>&1");
if ($result == ""){
$options = ["bypass_shell" => true];
$proc=proc_open("java JavaScannerExample",
  array(
    array("pipe","r"),
    array("pipe","w"),
    array("pipe","w")
  ),
  $pipes,NULL,NULL,$options);
if (is_resource($proc)) {   
   fwrite($pipes[0], 'Mark');
   fwrite($pipes[0], 32);
   fclose($pipes[0]);
   echo stream_get_contents($pipes[1]); 
   fclose($pipes[1]);
}

}
else{
    echo $result;
}
?>

Java Code

import java.util.Scanner;

public class JavaScannerExample
{

  public static void main (String[] args)
  {
    // create a scanner so we can read the command-line input
    Scanner scanner = new Scanner(System.in);

    //  prompt for the user's name
    System.out.print("Enter your name: ");

    // get their input as a String
    String username = scanner.next();

    // prompt for their age
    System.out.print("Enter your age: ");

    // get the age as an int
    int age = scanner.nextInt();

    System.out.println(String.format("%s, your age is %d", username, age));

  }

}

PHP Output

Enter your name: Enter your age:

Could you please check and let me know where did I went wrong?


Update2:

@Chris.. Thanks for your suggestion. It helped me get the output.

Here is the modified php code:

putenv('path=C:\Program Files\Java\jdk1.8.0_73\bin');
$result = shell_exec("javac JavaScannerExample.java 2>&1");
if ($result == ""){
    $options = ["bypass_shell" => true];
    $proc=proc_open("java JavaScannerExample",
            array(
                    array("pipe","r"),
                    array("pipe","w"),
                    array("pipe","w")
            ),
            $pipes,NULL,NULL,$options);
    if (is_resource($proc)) {
        fwrite($pipes[0], "Mark\n");
        fwrite($pipes[0], "32\n");
        fclose($pipes[0]);
        echo stream_get_contents($pipes[1]);
        fclose($pipes[1]);
    }
}
else{
    echo $result;
}

This is the result I am getting.

Enter your name: Enter your age: Mark, your age is 32

There are multiple problems with this type of result. First I am trying to build an interactive console. So for the above example, the pipes need to work in parallel. However, I am not able to retrieve pipes[1] until I close pipes[0]. Because if I get the value of pipes[1] earlier in the code the program is hanging. In this scenario. First I need to be able to read the input which is "Enter your name:" Then enter input which is "Mark". Next steps are similar I need to get the text "Enter age:" and enter input "32". finally I need to get the final output which is "Mark, your age is 32" and detect the program is finished and then close both the pipes. Is this possible?


Solution

  • Use proc_open instead of exec. It can be used to retrieve a pipe to stdin which can be used to provide input to your Java application. The first example on the proc_open manual page demonstrates how to do this.