I am trying to run a process on a web page that will return its output in realtime. For example if I run 'ping' process it should update my page every time it returns a new line (right now, when I use exec(command, output) I am forced to use -c option and wait until process finishes to see the output on my web page). Is it possible to do this in php?
I am also wondering what is a correct way to kill this kind of process when someone is leaving the page. In case of 'ping' process I am still able to see the process running in the system monitor (what makes sense).
This worked for me:
$cmd = "ping 127.0.0.1";
$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("pipe", "w") // stderr is a pipe that the child will write to
);
flush();
$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());
echo "<pre>";
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
print $s;
flush();
}
}
echo "</pre>";
This is a nice way to show real time output of your shell commands:
<?php
header("Content-type: text/plain");
// tell php to automatically flush after every output
// including lines of output produced by shell commands
disable_ob();
$command = 'rsync -avz /your/directory1 /your/directory2';
system($command);
You will need this function to prevent output buffering:
function disable_ob() {
// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
// Implicitly flush the buffer(s)
ini_set('implicit_flush', true);
ob_implicit_flush(true);
// Clear, and turn off output buffering
while (ob_get_level() > 0) {
// Get the curent level
$level = ob_get_level();
// End the buffering
ob_end_clean();
// If the current level has not changed, abort
if (ob_get_level() == $level) break;
}
// Disable apache output buffering/compression
if (function_exists('apache_setenv')) {
apache_setenv('no-gzip', '1');
apache_setenv('dont-vary', '1');
}
}
It doesn't work on every server I have tried it on though, I wish I could offer advice on what to look for in your php configuration to determine whether or not you should pull your hair out trying to get this type of behavior to work on your server! Anyone else know?
Here's a dummy example in plain PHP:
<?php
header("Content-type: text/plain");
disable_ob();
for($i=0;$i<10;$i++)
{
echo $i . "\n";
usleep(300000);
}
I hope this helps others who have googled their way here.
Checked all answers, nothing works...
Found solution Here
It works on windows (i think this answer is helpful for users searching over there)
<?php
$a = popen('ping www.google.com', 'r');
while($b = fgets($a, 2048)) {
echo $b."<br>\n";
ob_flush();flush();
}
pclose($a);
?>
A better solution to this old problem using modern HTML5 Server Side Events is described here:
http://www.w3schools.com/html/html5_serversentevents.asp
Example:
http://sink.agiletoolkit.org/realtime/console
Code: https://github.com/atk4/sink/blob/master/admin/page/realtime/console.php#L40
(Implemented as a module in Agile Toolkit framework)
For command-line usage:
function execute($cmd) {
$proc = proc_open($cmd, [['pipe','r'],['pipe','w'],['pipe','w']], $pipes);
while(($line = fgets($pipes[1])) !== false) {
fwrite(STDOUT,$line);
}
while(($line = fgets($pipes[2])) !== false) {
fwrite(STDERR,$line);
}
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
return proc_close($proc);
}
If you're trying to run a file, you may need to give it execute permissions first:
chmod('/path/to/script',0755);
try this (tested on Windows machine + wamp server)
header('Content-Encoding: none;');
set_time_limit(0);
$handle = popen("<<< Your Shell Command >>>", "r");
if (ob_get_level() == 0)
ob_start();
while(!feof($handle)) {
$buffer = fgets($handle);
$buffer = trim(htmlspecialchars($buffer));
echo $buffer . "<br />";
echo str_pad('', 4096);
ob_flush();
flush();
sleep(1);
}
pclose($handle);
ob_end_flush();
I've tried various PHP execution commands on Windows and found that they differ quite a lot.
Don't work for streaming: shell_exec, exec, passthru
Kind of works: proc_open, popen -- "kind of" because you cannot pass arguments to your command (i.e. wont' work with my.exe --something, will work with _my_something.bat).
The best (easiest) approach is:
You must make sure your exe is flushing commands (see printf flushing problem). Without this you will most likely receive batches of about 4096 bytes of text whatever you do.
If you can, use header('Content-Type: text/event-stream'); (instead of header('Content-Type: text/plain; charset=...');). This will not work in all browsers/clients though! Streaming will work without this, but at least first lines will be buffered by the browser.
You also might want to disable cache header('Cache-Control: no-cache');.
Turn off output buffering (either in php.ini or with ini_set('output_buffering', 'off');). This might also have to be done in Apache/Nginx/whatever server you use in front.
Turn of compression (either in php.ini or with ini_set('zlib.output_compression', false);). This might also have to be done in Apache/Nginx/whatever server you use in front.
So in your C++ program you do something like (again, for other solutions see printf flushing problem):
Logger::log(...) {
printf (text);
fflush(stdout);
}
In PHP you do something like:
function setupStreaming() {
// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
// Disable Apache output buffering/compression
if (function_exists('apache_setenv')) {
apache_setenv('no-gzip', '1');
apache_setenv('dont-vary', '1');
}
}
function runStreamingCommand($cmd){
echo "\nrunning $cmd\n";
system($cmd);
}
...
setupStreaming();
runStreamingCommand($cmd);
First check whether flush() works for you. If it does, good, if it doesn't it probably means the web server is buffering for some reason, for example mod_gzip is enabled.
For something like ping, the easiest technique is to loop within PHP, running "ping -c 1" multiple times, and calling flush() after each output. Assuming PHP is configured to abort when the HTTP connection is closed by the user (which is usually the default, or you can call ignore_user_abort(false) to make sure), then you don't need to worry about run-away ping processes either.
If it's really necessary that you only run the child process once and display its output continuously, that may be more difficult -- you'd probably have to run it in the background, redirect output to a stream, and then have PHP echo that stream back to the user, interspersed with regular flush() calls.
If you're looking to run system commands via PHP look into, the exec documentation.
I wouldn't recommend doing this on a high traffic site though, forking a process for each request is quite a hefty process. Some programs provide the option of writing their process id to a file such that you could check for, and terminate the process at will, but for commands like ping, I'm not sure that's possible, check the man pages.
You may be better served by simply opening a socket on the port you expect to be listening (IE: port 80 for HTTP) on the remote host, that way you know everything is going well in userland, as well as on the network.
If you're attempting to output binary data look into php's header function, and ensure you set the proper content-type, and content-disposition. Review the documentation, for more information on using/disabling the output buffer.
Try changing the php.ini file set "output_buffering = Off". You should be able to get the real time output on the page
Use system command instead of exec.. system command will flush the output
why not just pipe the output into a log file and then use that file to return content to the client. not quite real time but perhaps good enough?
I had the same problem only could do it using Symfony Process Components ( https://symfony.com/doc/current/components/process.html )
Quick example:
<?php
use Symfony\Component\Process\Process;
$process = new Process(['ls', '-lsa']);
$process->run(function ($type, $buffer) {
if (Process::ERR === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
?>
I'm trying to make a GUI for hosting Minecraft CraftBukkit servers in C#. CraftBukkit servers are hosted with a .jar which's source code can be found here: https://github.com/Bukkit/CraftBukkit/.
So far I am able to receive output from it and give input to it like this:
var serverProcInfo = new ProcessStartInfo("javaw",
"-jar -Xms" + Ram + "M -Xmx" + Ram + "M \"" +
JarFileLocation + "\" -nojline " + AdditionalParams)
{
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
serverProc = new Process {StartInfo = serverProcInfo };
serverProc.OutputDataReceived += ServerOutputDataReceived;
serverProc.ErrorDataReceived += ServerOutputDataReceived;
serverProc.BeginOutputReadLine();
serverProc.BeginErrorReadLine();
serverProc.WaitForExit();
I want to create a list of all the players that are currently online.
When a player joins a message like this is outputed player < playername > has joined the server. I know that I could split this string and get the player name, but I think that it is not very good since somebody may say something like that in chat, and my program could interpret it as if somebody joined the server.
I saw other programs do this ("BukkitGUI"), but I'm not sure how I could do this. Does the .jar file output the player list? What should I look for in its source code to see what it outputs?
I am relatively new to C# and have never learned Java. Any help would be appreciated.
EDIT1:
I found that the CraftBukkit.jar has a class like this:
#SuppressWarnings("unchecked")
public Player[] getOnlinePlayers() {
List<EntityPlayer> online = playerList.players;
Player[] players = new Player[online.size()];
for (int i = 0; i < players.length; i++) {
players[i] = online.get(i).playerConnection.getPlayer();
}
return players;
}
Is there any way I can call this class?
Unfortunately cross-process communication between java and C# is not so simple. Your best bet is to either send the list command to the server and parse the output, or if you're willing to write some java you could create a plugin for the minecraft server that opens a socket and send information back and forth.
I find a solution to this. It is actually quite easy.
First I create a process that will start the .jar file. Then I do the following:
Process.OutputDataReceived += ServerOutputHandler.ServerOutputReceived;
Process.ErrorDataReceived += ServerOutputHandler.ServerOutputReceived;
and after I start the process (Process.Start):
Process.BeginOutputReadLine();
Process.BeginErrorReadLine();
If you want to know more about handling .jar files, feel free to take a look at my open source project (I gave up it a while ago) ServerCrafter. For the part of the source code where I do code I mention above, take a look here: Server Crafter source code: ServerCrafter\ServerCrafter.ClassLibrary\ClassLibrary\Server\Server.cs
What commands do you use to talk to a GPIB instrument in C#, visual studio?
I need to be able to write commands to the instrument and read the output.
I use Agilent IO Library Suite.
Here is a tutorial to use it on C#: I/O programming examples in C#
Nevertheless, in my company we had stability issues with the VISA-COM implementation, so we wrote our own wrapper around the visa32.dll (also part of the IO Library suite) using P/Invoke.
(Disclosure: I work in a company that make intense use of GPIB instruments)
I'm using National Instruments VISA and NI 488.2.
First make sure that you checked the VisaNS.NET API in the NI-VISA Setup, see the following figure:
Add a reference to NationalInstruments.VisaNS and NationalInstruments.Common to your project.
Create a MessageBasedSession, see the following code:
string resourceName = "GPIB0::20::INSTR"; // GPIB adapter 0, Instrument address 20
var visa = new NationalInstruments.VisaNS.MessageBasedSession(resourceName);
visa.Write("*IDN?"); // write to instrument
string res = visa.ReadString(); // read from instrument
A MessageBasedSession can be used to communicate with your instrument over GPIB, Ethernet or USB.
Update
Ivi.Visa superseded NationalInstruments.VisaNS. So you should add a reference only to Ivi.Visa to your project.
The example would look like that:
string resourceName = "GPIB0::20::INSTR"; // GPIB adapter 0, Instrument address 20
var visa = GlobalResourceManager.Open(resourceName) as IMessageBasedSession;
visa.RawIO.Write("*IDN?\n"); // write to instrument
string res = visa.RawIO.ReadString(); // read from instrument
The benefit of using Ivi.Visa is that it works with one of the following libraries:
National Instruments VISA
Keysight IO Libraries Suite
Rohde & Schwarz VISA
Send commands out the serial port.
See Microsoft's COM Port Example.
You should create an object with LangInt class first. Then use that object with GPIB methods.
Most common and used ones are(assuming you created an object named "dev");
dev.ibwrt(deviceHandle, "*IDN?", "*IDN?".Length);
dev.ibrd(deviceHandle, out Value, Arraysize);
These two can query the device. Or you can use them consecutively for example setting a generator's frequency and then it's amplitude.
Important part is before sending SCPI commands; you MUST initialize devices first. To do this use;
deviceHandle = ibdev(GPIBINDEX, GPIBADDRESS, SECONDARYADDRESS, TIMEOUT, EOTMODE, EOSMODE);
These parameters must declared first within the code. After initialization you can use every GPIB command with that device handles.
And of course you should add NationalInstruments.NI4882 and LangInt.dll to your project.
You can use NI Visa.
If you are using Vb or C# use Visa32.bas or Visa32.cs from the sample programs disk
int DefaultSessionId= 0;
int SessionId= 0;
int LastStatus = 0;
string Address = "GPIB0::6" ; //any address
//Session Open
LastStatus = visa32.viOpenDefaultRM(out DefaultSessionId);
//Connection Open
LastStatus = visa32.viOpen(DefaultSessionId, Address + "::INSTR", 0, 0, out sessionId);
LastStatus = visa32.viSetAttribute(SessionId, visa32.VI_ATTR_TERMCHAR, 13);// Set the termination character to carriage return (i.e., 13);
LastStatus = visa32.viSetAttribute(SessionId, visa32.VI_ATTR_TERMCHAR_EN, 1);// Set the flag to terminate when receiving a termination character
LastStatus = visa32.viSetAttribute(SessionId, visa32.VI_ATTR_TMO_VALUE, 2000);// Set timeout in milliseconds; set the timeout for your requirements
//Communication
LastStatus = visa32.viPrintf(SessionId, command + "\n");//device specific commands to write
StringBuilder message = new StringBuilder(2048);
LastStatus = visa32.viScanf(SessionId, "%2048t", message);//Readback
//Session and Connection Close
visa32.viClose(SessionId);
visa32.viClose(DefaultSessionId);
Reference
I'm trying to get a C++ service to load an XML document from a MSMQ message generated by C#. I can't really change the C++ side of things because I'm trying to inject test messages into the queue. The C++ service is using the following to load the XML.
CComPtr<IXMLDOMDocument2> spDOM;
CComPtr<IXMLDOMNode> spNode;
CComBSTR bstrVal;
if(_FAILED(hr = spDOM.CoCreateInstance(CLSID_DOMDocument30)))
{
g_infoLog->LogCOMError(hr, "CWorker::ProcessBody() Can't Create DOM");
pWork->m_nFailure = WORKFAIL_BADXML;
goto Exit;
}
hr = spDOM->loadXML(bstrBody, &vbResult);
The C# code to send the MSMQ message looks like this (just test code not pretty):
// open the queue
var mq = new MessageQueue(destinationQueue)
{
// store message on disk at all intermediaries
DefaultPropertiesToSend = { Recoverable = true },
// set the formatter to Binary, default is XML
Formatter = new BinaryMessageFormatter()
};
// send message
mq.Send(messageContent, "TestMessage");
mq.Close();
I tried to send the same message using BinaryMessageFormatter but it puts what I think are unicode characters at the top before the XML starts.
.....ÿÿÿ
ÿ.......
......À)
If I use the default XML formatter the message has the following top element. The C++ service doesn't seem to handle this.
<?xml version="1 .0"?>..<string>& lt;
Do you know of a way I could easily clean up the unicode characters when using the binary formatter? If so I think it might work.
Have you tried the ActiveXMessageFormatter? It might not compile with it as the formatter, i have no way to test here, but it might.
EDIT: just tried and it compiles ok, whether the result is any better i still couldn't say for sure.
I am currently trying to develop a program which takes the output of an existing program (written in C) and uses it as input (in C#). The problem I am having is that the existing program prints data in redundant format but it dynamically changes. An example could be a random name generator and I need to make a program that logs all of the random names as they appear.
Could I just pipe this and the output will be grabbed as it comes? The C program is run from a CLI.
You could redirect the output streams from the Process object to get direct access to it. You make a call and it will invoke an event of your choice when output is received. One of my questions may provide some explanation on how to do this - C# Shell - IO redirection:
processObject.StartInfo.RedirectStandardOutput = true;
processObject.OutputDataReceived += new DataReceivedEventHandler(processObject_OutputDataReceived);
/* ... */
processObject.Start();
processObject.BeginOutputReadLine();
And then later:
public void processObject_OutputDataReceived(object sender, DataReceivedEventArgs e) {
ProcessNewData(e.Data);
}
Note that this includes the trailing newline.
Or you can just pipe it and use Console.ReadLine to read it in. On the command line, you would execute:
cprogram | csharp_program
Unfortunately, you can't do this directly with the Process object - just use the method above. If you do choose to go this route, you can use:
string input = "";
int currentChar = 0;
while ( (currentChar = Console.Read()) > -1 ) {
input += Convert.ToChar(currentChar);
}
Which will read from the input until EOF.
If the C# program is also command-line based, running this command from the command-line will chain them together:
my_c_program.exe | my_csharp_program.exe
The C# program will receive the output of the C program, via its standard input stream (Console.Read, etc.)