Working with PHP STDIN and proc_open and Node JS command - php

I'm trying to utilize a node js package called can-compile which reads the contents from an ejs file and then converts the data to a usable and canjs friendly output. I'm trying to avoid saving the template data to a file on the server and using said file to convert the template data. That is where I have been trying to use php's STDIN/OUT.
The compiler takes the name of the template file as a parameter to read from. I've tried various methods of passing the template data to node command line with no success.
Ultimately what I'm trying to achieve is being able to send the uncompiled template data to the STDIN/OUT pipe and have it return the compiled code from the can-compile node package.
Can someone please point me in the right direction of what I should be doing. Here I'm using a small template example (see $input). But the template sizes vary up to hundreds of lines and characters.
$template_name = 'template_'.$template_data['name'].'.ejs';
$can_compiler = "/node_modules/can-compile/bin/can-compile --can 1.1.5 $template_name";
$input = "<img src="/media/<%==category.attrs.image%>" style="width:100%; height:100%;" />";
$cmd = sprintf("node %s",$can_compiler);
$descriptorspec = array(
0 => array('pipe','r'),
1 => array('pipe','w'),
2 => array('pipe','w')
);
$process = proc_open($cmd, $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], $input);
fclose($pipes[0]);
$template_content = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$error_content = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$return_value = proc_close($process);
return $template_content;
}
I've already search through stack-overflow and found this How to pass variables as stdin into command line from PHP. The strange issue I'm running into is that my code has worked yesterday but not today. Maybe a fresh set of eyes can help me out.

I have figured out the issue, I was missing the file_put_contents() function when sending data to the pipe...
Here is the working code...
$template_name = 'template_test.ejs';
$input = '<img src="/media/<%==category.attrs.image%>" style="width:100%; height:100%;" />';
$cmd = "node /node_modules/can-compile/bin/can-compile --can 1.1.5 $template_name";
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w")
);
$process = proc_open($cmd, $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], file_put_contents($template_name,$input));
fclose($pipes[0]);
$template_name = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$return_value = proc_close($process);
echo $template_name;
}

Related

PHP - `shell_exec` not working with NMap (Windows Server)

I've been trying to figure out why I can't get NMap to give me any sort of output nor even work for that matter via PHP.
Things I've tried so far:
// this doesn't return anything because it's wrong
$output = passthru('nmap -V');
echo $output;
// this returns a negated integer value
passthru('nmap -V', $output);
echo $output;
// this doesn't return anything either
$stream = popen('C:\nmap -V', 'r');
while (!feof($stream))
{
$buffer = fread($stream, 1024);
echo $buffer;
}
pclose($stream);
// this doesn't do anything as well
$output = system('C:\nmap -V');
echo $output;
// this does nothing also...
ob_start(); // start output buffering
fpassthru('C:\nmap -V'); // flush COMPLETE output of nmap
$output = ob_get_contents(); // capture output buffer contents
ob_end_clean(); // shutdown output buffers
echo $output; // echo it
.
// okay, how about we try a 'proc_open()'?
// nope, this doesn't work either. I just get a value of "command returned -1073741515"
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "errors/errors.txt", "a") // stderr is a file to write to
);
$cwd = 'errors';
$env = array('some_option' => 'aeiou');
$process = proc_open('C:/nmap -V', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process))
{
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be appended to /errors/errors.txt
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
echo "command returned $return_value\n";
}
And many others, but I get absolutely NOTHING back from $output. I've done a lot of Google searching too, but I still can't figure it out. Many examples also seem to be for Linux which doesn't help.
Thanks.
Okay, I get an output using this code. I will continue coding and finish the rest of the program. Thanks to 'Chris Haas' for the suggestion in using proc_open
NOTE: The directory that contains the 'errors.txt' file must have 'IIS_IUSRS' write permissions. When in doubt, check your PHP error log.
$descriptorSpec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "errors/errors.txt", "a") // stderr is a file to write to
);
$env = array('bypass_shell' => true);
$process = proc_open("NMAP.EXE -V", $descriptorSpec, $pipes, "C:\\Program Files (x86)\\NMap", $env);
if (is_resource($process))
{
// '$pipes' now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// it is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
echo "<br /><br />Command Returned: $return_value\n";
}
Nmap version 7.91 ( https://nmap.org ) Platform:
i686-pc-windows-windows Compiled with: nmap-liblua-5.3.5
openssl-1.1.1h nmap-libssh2-1.9.0 nmap-libz-1.2.11 nmap-libpcre-7.6
Npcap-1.00 nmap-libdnet-1.12 ipv6 Compiled without: Available nsock
engines: iocp poll select
Command Returned: 0

php -> fwrite to process pipe hangs -> why?

Can anyone say, why the following code hangs on fwrite($pipes[0], $data);, but it does not hang when I change $bytesCount to, for example, 1000?
I was not able to find answer via google :(
Thank you.
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w")
);
$bytesCount = 1000000;
$process = proc_open('cat', $descriptorspec, $pipes);
$data = str_repeat('a', $bytesCount);
fwrite($pipes[0], $data);
fclose($pipes[0]);
$response = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$return_value = proc_close($process);
Pipes are implemented with input and output buffers. cat starts to read, and copies everything to the output. When the output buffer is full, its write is blocked.
Since nothing is reading cat's input (as that line is never reached), it will block indefinitely, blocking your fwrite.

PHP SVN update - TortoiseSVN

New code:
<?php
exec('"C:\Program Files\TortoiseSVN\bin\svn.exe" update "c:\wamp\www\project"');
This results in an infinite loop, no result is returned. What am I doing wrong?
== edit ==
On Windows, I'm trying to update a project by using PHP. I'm having problems using the commandline: I want visual feedback (important in case of conflicts), so I don't want to start as a background process. Is this possible?
The code I have so far is:
<?php
$todo = "cd \"C:\\Program Files\\TortoiseSVN\\bin\\\"";
$todo2 = "START TortoiseProc.exe /command:update /path:\"C:\\wamp\\www\\project\\\" /closeonend:0";
pclose(popen($todo, "r"));
pclose(popen($todo2, "r"));
I would drop exec and use proc_open (see http://php.net/manual/en/function.proc-open.php)
Here's an example I quickly whipped up and which should work for you:
<?php
// setup pipes that you'll use
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
// call your process
$process = proc_open('"C:\Program Files\TortoiseSVN\bin\svn.exe" update "c:\wamp\www\project"',
$descriptorspec,
$pipes);
// if process is called, pipe data to variables which can later be processed.
if(is_resource($process))
{
$stdin = stream_get_contents($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value = proc_close($process);
}
// Now it's up to you what you want to do with the data you've got.
// Remember that this is merely an example, you'll probably want to
// modify the output handling to your own likings...
header('Content-Type: text/plain; charset=UTF-8');
// check if there was an error, if not - dump the data
if($return_value === -1)
{
echo('The termination status of the process indicates an error.'."\r\n");
}
echo('---------------------------------'."\r\n".'STDIN contains:'."\r\n");
echo($stdin);
echo('---------------------------------'."\r\n".'STDOUTcontains:'."\r\n");
echo($stdout);
echo('---------------------------------'."\r\n".'STDERR contains:'."\r\n");
echo($stderr);
?>
Aside:
The line
// call your process
$process = proc_open('"C:\Program Files\TortoiseSVN\bin\svn.exe" update "c:\wamp\www\project"',
$descriptorspec,
$pipes);
could also be escaped like this
// call your process
$process = proc_open("\"C:\\Program Files\\TortoiseSVN\\bin\\svn.exe\" update \"c:\\wamp\\www\\project\"",
$descriptorspec,
$pipes);
which might or might not solve some problems on some systems that have hickups with the single brackets (') and spaces () in the notation.

Displaying Errors in online c compiler

Hi all I have a c compiler up and running shows the output but the problem is that it dosen't show errors....
shell_exec("gcc xyz.c -o ab.out ");
$output=exec("./ab.out");
echo $output;
So it is showing output but not any errors occurred while compiling.
Any help is duly appreciated.
Thanks in advance.
Any error output from the command you run will go to STDERR and none of the exec, shell_exec functions will provide you that. One way is to redirect it
exec("gcc test.c 2>&1", $out);
The most cleaner way is to use proc_open function.
$descriptorspec = array(
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$process = proc_open('gcc test.c', $descriptorspec, $pipes);
if (is_resource($process)) {
$stderr = stream_get_contents($pipes[2]);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value = proc_close($process);
}

Run .exe in web app and real-time communication with this .exe

My PHP web app receives data from a stream. Once the page is loaded I need to open an .exe file using system() or exec() and after short period of time new data will come, so I must type specific command to this .exe to get its returned value, how can I do this?
I'm only able to do this manually in command prompt
path/to/.exe :: hit 'Enter'
command1 params1
//...
What you're looking for is proc_open(). http://php.net/manual/en/function.proc-open.php
This will allow you to work with STDIO streams to communicate with the separate process.
Example from the PHP documentation:
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
);
$cwd = '/tmp';
$env = array('some_option' => 'aeiou');
$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be appended to /tmp/error-output.txt
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
echo "command returned $return_value\n";
}
You could also consider shared memory if you need more than one listener, but this scenario sounds like you would benefit from using a queue.
Documentation msg_get_queue, msg_receive, msg_send
Example
// Send
if (msg_queue_exists(12345)) {
$mqh = msg_get_queue(12345);
$result = msg_send($mqh , 1, 'data', true);
}
// Receive
$mqh = msg_get_queue(12345, 0666);
$mqst = msg_stat_queue($mqh);
while ($mqst['msg_qnum']) {
msg_receive($mqh, 0, $msgtype, 2048, $data, true);
// Spawn your process
$mqst = msg_stat_queue($mqh);
}
Edit
Semaphore functions aren't available on Windows, as suggested above your best bet is to go with popen (unidirectional) or proc_open for bi-directional support.

Categories