tags:

views:

1982

answers:

6

I'm trying to get the PHP parser to run a page and then return the results to my server, however when I run the command via my code, it returns nothing. I know the command is correct because if I run it manually with the same path, it works fine. Heres my code:

var p = new Process
{
      StartInfo = new ProcessStartInfo("C:\\xampp\\php\\php.exe", path)
      {
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            CreateNoWindow = true
      }
};
var output = new StringWriter();
var error = new StringWriter();
p.OutputDataReceived += (sender, args) => output.WriteLine(args.Data);
p.ErrorDataReceived += (sender, args) => error.WriteLine(args.Data);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
if (p.ExitCode != 0)
{
      throw new Exception(string.Format(
          "PHP failed with the following output:{0}{1}",
      /* {0} */ Environment.NewLine,
      /* {1} */ error.GetStringBuilder().ToString()));
}
var res = output.GetStringBuilder().ToString();
Console.WriteLine(res);

EDIT: With this current code, it throws the exception in the code with no output.

+5  A: 

The problem is that you are reading the output before the program finishes. You need to wait for program exit to process the output. Otherwise you'll be processing the output before the parse is complete. Add the following line in.

p.Start();
p.WaitForExit();  // New line

EDIT OP said they are still having problems.

Try removing the CMD portion of the command. Just run the PHP command directly. It also may be beneficial to allow the creation of a window for debugging purposes so you can see any errors that may come out of running the command.

JaredPar
You got me, +1 :)
Martín Marconcini
hrm, I tried this, but I still seem to have the same problem
The.Anti.9
Hrm, I tried removing the cmd part, but then it gives me an exception that says "The filename, directory name, or volume label syntax is incorrect"
The.Anti.9
+1  A: 

ReadToEnd() just reads the entire contents of the stream as they are at that point in time. Given that you're calling this immediately after Start(), the stream is likely empty. You have a couple of options

  • Call ReadLine() instead, but this will only read one line
  • p.WaitForExit() then call ReadToEnd(), but I am not certain this keeps the stream open. If this does, then this is your best option.
Adam Robinson
+1  A: 

You need to add p.WaitForExit(); after the p.Start(); else the output is not ready when you try to read it.

Martín Marconcini
A: 

Is there a reason you're running php through cmd? Can't you just execute it directly?

It has been my experience that executing processes through .NET is the worst way to execute another process. fork() under unix is amazingly much better. I have had so many issues that my advice is that you STRONGLY consider looking at Process.BeginOutputReadLine() and go the asynchronous route in your reading. ReadToEnd and ReadToLine can hang indefinitely especially if you have lengthy output to capture.

I would paste an example but it is rather lengthy.

Colin Burnett
I would like to try this, but in my opinion, the example on MSDN is rather poor, could you please post your example?
The.Anti.9
The class I wrote to wrap all this is at work.In the interim, the gist is a class that sets Process.OutputDataReceived to a class static method that concats the string to a growing private class string. When done executing the process you access the string via a public property. You can do the same thing for stderr as stdout. Effectively, it's what Process should be. :)
Colin Burnett
I tried that, but it didn't work either.
The.Anti.9
+2  A: 

The most robust way to invoke the process and capture its output or error would to try it the following way:

var p = new Process {
    StartInfo = new ProcessStartInfo("php", path) {
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        UseShellExecute = false,
        CreateNoWindow = true
    }
};
var output = new StringWriter();
var error = new StringWriter();
p.OutputDataReceived += (sender, args) => output.WriteLine(args.Data);
p.ErrorDataReceived += (sender, args) => error.WriteLine(args.Data);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
if (p.ExitCode != 0) {
    throw new Exception(string.Format(
        "PHP failed with the following output:{0}{1}",
        /* {0} */ Environment.NewLine,
        /* {1} */ error.GetStringBuilder().ToString()));
}
var res = output.GetStringBuilder().ToString();
Console.WriteLine(res);
Atif Aziz
OK i tried this, I had to edit the command part. changed it to "cmd", "/c php " + path. and then i got this as the error output: "'php' is not recognized as an internal or external command,operable program or batch file." But the weird thing about this is that the php command works if i open up the command prompt and run it...
The.Anti.9
Try specifying the full, absolute, path to the php executable as the first argument to the ProcessStartupInfo constructor. Using "cmd" is an overkill.
Atif Aziz
Ok, I tried this and it threw the exception with blank output.
The.Anti.9
+3  A: 

Set WorkingDirectory Path

var p = new Process
            {
                StartInfo = new ProcessStartInfo("php", path)
                {
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    WorkingDirectory = workingDir
                }
            };
Vikram Sudhini
Throws an exception on p.Start() with this message: "The system cannot find the file specified"
The.Anti.9
can you elaborate on the error that you got? if it cant find the php.exe then try full path eg:StartInfo = new ProcessStartInfo("C:\\xampp\\php\\php.exe", path)
Vikram Sudhini
This worked. Thanks!
The.Anti.9