This PHP snippet should execute a simple command via SSH (stripped down to minimal working example):
$sshconn = ssh2_connect($HostAddr, 22);
ssh2_auth_pubkey_file($sshconn, $user, $sshkey . '.pub', $sshkey);
$stdout = ssh2_exec($sshconn, 'echo hello');
if ($stdout !== false)
{
stream_set_blocking($stdout, true);
while (!feof($stdout))
{
$proc_stdout = fgets($stdout, 3E6);
if ($proc_stdout !== false) echo $proc_stdout;
}
fclose($stdout);
}
Works great as long as there is any output to stdout. However, if stdout remains empty, the loop turns into an endless loop.
$stdout = ssh2_exec($sshconn, 'echo hello >&2');
How do I read the stdout properly if
stdout may be empty
but stdout may also very large (several Gigabytes, impossible to slurp into a variable by a single call to stream_get_contents or the like).
Addendum: My real world code that hangs executes mysqldump with an unknown parameter. Obviously, echo -n >&2 works as expected, although its stdout is also empty.
If anyone stumbles upon this too: stderr has to be read too.
$sshconn = ssh2_connect($HostAddr, 22);
ssh2_auth_pubkey_file($sshconn, $user, $sshkey . '.pub', $sshkey);
$stdout = ssh2_exec($sshconn, 'echo Hello >&2');
if ($stdout !== false)
{
$stderr = ssh2_fetch_stream($stdout, SSH2_STREAM_STDERR);
stream_set_blocking($stdout, false);
stream_set_blocking($stderr, false);
while (!feof($stdout))
{
$proc_stdout = fgets($stdout, 3E6);
if ($proc_stdout !== false) echo $proc_stdout;
$proc_stderr = fgets($stderr, 3E6);
if ($proc_stderr !== false) fwrite(STDERR, $stderr);
}
fclose($stdout); fclose($stderr);
}
The disadvantage of this is that the SSH connection is no longer usable afterwards (a further ssh2_exec cannot be executed).
A possible solution is to keep both streams blocking and read stdout and stderr non-interleaved:
$stdout = ssh2_exec($sshconn, 'echo Hello >&2');
$stderr = ssh2_fetch_stream($stdout, SSH2_STREAM_STDERR);
stream_set_blocking($stdout, true);
stream_set_blocking($stderr, true);
while ($content = fread($stdout, 3E6)) echo $content;
while ($content = fread($stderr, 3E6)) fwrite(STDERR, $content);
I invite anyone who knows how to have the streams interleaved and keep the SSH connection usable to post another answer.
I'm writing a wrapper for mysqldump and want to show the output nicely in a PHP CLI application.
I'm attempting to run mysqldump -v using popen so that I can get the verbose output and display progress indicators to the user. However no output is returned (by default it gets logged to the screen via stdErr).
I tried adding 2>&1 to the command to push the verbose output from stdErr to stdOut, but fread still doesn't get any output even though the output nolonger goes to the screen via stdErr.
$cmd = "mysqldump -uroot -proot -v dbname 2>&1 | mysql -uroot -proot dbname2";
$handle = popen($cmd, "r");
$buffer = "";
while ($handle && !feof($handle)){
$output = fread($handle, 100);
$buffer .= $output;
echo sprintf("Buffer: %s\n", $buffer);
}
pclose($handle);
Should I use something else instead of popen? Or am I simply incorrectly redirecting the output?
You seem to actually pipe the mysqldump data into mysql, in which case it might be a bad idea to include error messages into the pipe.
Of course, in this scenario, you cannot capture the mysqldump's output.
You should use the tee command:
mysqldump -uroot -proot -v dbname | tee /tmp/output | mysql -uroot -proot dbname2
This way, you can have the output both in pipe for mysql and /tmp/output.
In such a way you can then fopen /tmp/output for results.
Please note that you might not have the possible errors in the output, as mysql would not be happy seeing them later down the pipe.
I figured it out, without having to use a file as a stream buffer.
/**
* PROCESS
*
* Process the command
*
* #param int $buffer The size of the buffer
* #param int $pipe The pipe to subscribe to (0=stdIn, 1=stdOut, 2=stdErr)
*
* #return bool Success or not
*/
public function process($buffer=10, $pipe=1) {
$handle = proc_open(
$this->command,
[
["pipe","r"],
["pipe","w"],
["pipe","w"]
],
$pipes
);
if (!is_resource($handle)) {
return false;
}
$output = "";
$buffer = "";
$hasLineCallbacks = count($this->onNewLine);
while ($buffer = fread($pipes[$pipe], 10)) {
$output .= $buffer;
if (preg_match("/[\r\n]/", $output)) {
$segments = preg_split("/[\r\n]+/", $output);
while (count($segments) > 1) {
$line = array_shift($segments);
if (!$hasLineCallbacks) { continue; }
foreach ($this->onNewLine as $callback) {
if (!$callback["pattern"] || preg_match($callback["pattern"], $line)) {
call_user_func($callback["callback"], $line);
}
}
}
$output = array_shift($segments);
}
}
proc_close($handle);
return true;
}
I'm basically making Background class to run a terminal command and pipe the output to callback functions. It obviously still has a long way to go though.
Thanks for your help, #Victor
I recently tried to communicate with a binary on my Ubuntu webserver [1] using the PHP function proc_open. I can establish a connection and define the pipes STDIN, STDOUT, and STDERR. Nice.
Now the bimary I am talking to is an interactive computer algebra software - therefore I would like to keep both STDOUT and STDIN alive after the first command such that I can still use the application a few lines later in an interactive manner (direct user inputs from a web-frontend).
However, as it turns out, the PHP functions to read the STDOUT of the binary (either stream_get_contents or fgets) need a closed STDIN before they can work. Otherwise the program deadlocks.
This is a severe drawback since I can not just reopen the closed STDIN after closing it. So my question is: why does my script deadlock if I want to read the STDOUT when my STDIN is still alive?
Thanks
Jens
[1] proc_open returns false but does not write in error file - permissions issue?
my source:
$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","./error.log","a")
) ;
// define current working directory where files would be stored
$cwd = './' ;
// open reduce
$process = proc_open('./reduce/reduce', $descriptorspec, $pipes, $cwd) ;
if (is_resource($process)) {
// some valid Reduce commands
fwrite($pipes[0], 'load excalc; operator x; x(0) := t; x(1) := r;');
// if the following line is removed, the script deadlocks
fclose($pipes[0]);
echo "output: " . stream_get_contents($pipes[1]);
// close pipes & close process
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
}
EDIT:
This code kind of works. Kind of because it uses usleeps to wait for the non-blocked STDOUT to be filled with data. How do I do that more elegantly?
# Elias: By polling the $status['running'] entry you can only determine if the overall process is still running, but not if the process is busy or idling... That is why I have to include these usleeps.
define('TIMEOUT_IN_MS', '100');
define('TIMEOUT_STEPS', '100');
function getOutput ($pipes) {
$result = "";
$stage = 0;
$buffer = 0;
do {
$char = fgets($pipes[1], 4096);
if ($char != null) {
$buffer = 0;
$stage = 1;
$result .= $char;
} else if ($stage == "1") {
usleep(TIMEOUT_IN_MS/TIMEOUT_STEPS);
$buffer++;
if ($buffer > TIMEOUT_STEPS) {
$stage++;
}
}
} while ($stage < 2);
return $result;
}
$descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w") ) ;
// define current working directory where files would be stored
$cwd = './' ;
// open reduce
$process = proc_open('./reduce/reduce', $descriptorspec, $pipes, $cwd);
if (is_resource($process)) {
stream_set_blocking($pipes[1], 0);
echo "startup output:<br><pre>" . getOutput($pipes) . "</pre>";
fwrite($pipes[0], 'on output; load excalc; operator x; x(0) := t; x(1) := r;' . PHP_EOL);
echo "output 1:<br><pre>" . getOutput($pipes) . "</pre>";
fwrite($pipes[0], 'coframe o(t) = sqrt(1-2m/r) * d t, o(r) = 1/sqrt(1-2m/r) * d r with metric g = -o(t)*o(t) + o(r)*o(r); displayframe;' . PHP_EOL);
echo "output 2:<br><pre>" . getOutput($pipes) . "</pre>";
// close pipes & close process
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
}
This reminds me of a script I wrote a while back. While it might serve as inspiration to you (or others), it doesn't do what you need. What it does contain is an example of how you can read the output of a stream, without having to close any of the streams.
Perhaps you can apply the same logic to your situation:
$allInput = array(
'load excalc; operator x; x(0) := t; x(1) := r;'
);//array with strings to pass to proc
if (is_resource($process))
{
$output = '';
$input = array_shift($allInput);
do
{
usleep(200);//make sure the running process is ready
fwrite(
$pipes,
$input.PHP_EOL,//add EOL
strlen($input)+1
);
fflush($pipes[0]);//flush buffered data, write to stream
usleep(200);
$status = proc_get_status($process);
while($out = fread($pipes[1], 1024) && !feof($pipes[1]))
$output .= $out;
} while($status['running'] && $input = array_shift($allInput));
//proc_close & fclose calls here
}
Now, seeing as I don't know what it is exactly you are trying to do, this code will need to be tweaked quite a bit. You may, for example, find yourself having to set the STDIN and STDOUT pipes as non-blocking.
It's a simple matter of adding this, right after calling proc_open, though:
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
Play around, have fun, and perhaps let me know if this answer was helpful in any way...
My guess would be that you're doing everything correctly, except that the binary is never notified that it has received all the input and can start to work. By closing STDIN, you're kicking off the work process, because it's clear that there will be no more input. If you're not closing STDIN, the binary is waiting for more input, while your side is waiting for its output.
You probably need to end your input with a newline or whatever other protocol action is expected of you. Or perhaps closing STDIN is the action that's expected of you. Unless the process is specifically created to stay open and continue to stream input, you can't make it do it. If the process reads all input, processes it, returns output and then quits, there's no way you can make it stay alive to process more input later. If the process explicitly supports that behaviour, there should be a definition on how you need to delimit your input.
Scenario: I needed a function to get STDOUT of a command run through SSH asynchronously. This has various uses including (and most importantly) reading files through SSH.
An important feature of this function is that it is asynchronous, hence I can display output as it is returned from the server (or give an estimate of the file download progress). This differs from the common approach of using ssh_move() to download files.
function ssh_exec($dsn, $cmd, $return=true, $size_est=null){
$BUFFER_SIZE = $return ? (1024 * 1024) : 1;
debug('ssh2_exec '.$cmd);
$stream = ssh2_exec(ssh_open($dsn), $cmd);
debug('stream_set_blocking');
stream_set_blocking($stream, true);
debug('ssh2_fetch_stream');
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
stream_set_blocking($stream_out, true);
debug('stream_get_contents');
$data = ''; $stime = $oldtime = microtime(true); $data_len = 0;
if(!$return){
write_message("\033[0m".' Execution Output:'.PHP_EOL.' ');
}
while(!feof($stream_out)){
$buff = fread($stream_out, $BUFFER_SIZE);
if($buff===false)throw new Exception('Unexpected result from fread().');
if($buff===''){
debug('Empty result from fread()...breaking.');
break;
}
$data .= $buff;
if($return){
$buff_len = strlen($buff);
$data_len += $buff_len;
$newtime = microtime(true);
debugo('stream_get_contents '.bytes_to_human($data_len)
.' # '.bytes_to_human($buff_len / ($newtime - $oldtime)).'/s'
.' ['.($size_est ? number_format($data_len / $size_est * 100, 2) : '???').'%]');
$oldtime = $newtime;
}else{
echo str_replace(PHP_EOL, PHP_EOL.' ', $buff);
}
}
if($return){
debugo('stream_get_contents Transferred '.bytes_to_human(strlen($data)).' in '.number_format(microtime(true) - $stime, 2).'s');
return $data;
}
}
Usage: The function is used like so:
$dsn = 'ssh2.exec://root:pass#host/';
$size = ssh_size($dsn, 'bigfile.zip');
$zip = ssh_exec($dsn, 'cat bigfile.zip', true, $size);
Note 1: An explanation of some non-standard functions:
debug($message) - Writes debug message to console.
ssh_open($dsn) - Takes in an SSH URI and returns an SSH connection handle.
bytes_to_human($bytes) - Converts the number of bytes to human readable format (eg: 6gb)
debugo($message) - The same as debug() but overwrites last line.
Note 2: The parameter $size_est is used in the progress indicator; usually you'd first get the file size and then attempt to download it (as in my example). It is optional so that it can be ignored when you just want to run an SSH command.
The Problem: Running the same download operation via scp root#host:/bigfile.zip ./, I get speeds up to 1mb/s whereas this script seems to limit to 70kb/s. I'd like to know why and how to improve this.
Edit: Also, I'd like to know how/if $BUFFER_SIZE does any difference.
You should be able to use phpseclib, a pure PHP SSH implementation, to do this. eg.
$ssh->exec('cat bigfile.zip', false);
while (true) {
$temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
if (is_bool($temp)) {
break;
}
echo $temp;
}
Might actually be faster too.
I need to execute a directory copy upon a user action, but the directories are quite large, so I would like to be able to perform such an action without the user being aware of the time it takes for the copy to complete.
Any suggestions would be much appreciated.
Assuming this is running on a Linux machine, I've always handled it like this:
exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));
This launches the command $cmd, redirects the command output to $outputfile, and writes the process id to $pidfile.
That lets you easily monitor what the process is doing and if it's still running.
function isRunning($pid){
try{
$result = shell_exec(sprintf("ps %d", $pid));
if( count(preg_split("/\n/", $result)) > 2){
return true;
}
}catch(Exception $e){}
return false;
}
Write the process as a server-side script in whatever language (php/bash/perl/etc) is handy and then call it from the process control functions in your php script.
The function probably detects if standard io is used as the output stream and if it is then that will set the return value..if not then it ends
proc_close( proc_open( "./command --foo=1 &", array(), $foo ) );
I tested this quickly from the command line using "sleep 25s" as the command and it worked like a charm.
(Answer found here)
You might want to try to append this to your command
>/dev/null 2>/dev/null &
eg.
shell_exec('service named reload >/dev/null 2>/dev/null &');
I'd just like to add a very simple example for testing this functionality on Windows:
Create the following two files and save them to a web directory:
foreground.php:
<?php
ini_set("display_errors",1);
error_reporting(E_ALL);
echo "<pre>loading page</pre>";
function run_background_process()
{
file_put_contents("testprocesses.php","foreground start time = " . time() . "\n");
echo "<pre> foreground start time = " . time() . "</pre>";
// output from the command must be redirected to a file or another output stream
// http://ca.php.net/manual/en/function.exec.php
exec("php background.php > testoutput.php 2>&1 & echo $!", $output);
echo "<pre> foreground end time = " . time() . "</pre>";
file_put_contents("testprocesses.php","foreground end time = " . time() . "\n", FILE_APPEND);
return $output;
}
echo "<pre>calling run_background_process</pre>";
$output = run_background_process();
echo "<pre>output = "; print_r($output); echo "</pre>";
echo "<pre>end of page</pre>";
?>
background.php:
<?
file_put_contents("testprocesses.php","background start time = " . time() . "\n", FILE_APPEND);
sleep(10);
file_put_contents("testprocesses.php","background end time = " . time() . "\n", FILE_APPEND);
?>
Give IUSR permission to write to the directory in which you created the above files
Give IUSR permission to READ and EXECUTE C:\Windows\System32\cmd.exe
Hit foreground.php from a web browser
The following should be rendered to the browser w/the current timestamps and local resource # in the output array:
loading page
calling run_background_process
foreground start time = 1266003600
foreground end time = 1266003600
output = Array
(
[0] => 15010
)
end of page
You should see testoutput.php in the same directory as the above files were saved, and it should be empty
You should see testprocesses.php in the same directory as the above files were saved, and it should contain the following text w/the current timestamps:
foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610
If you need to just do something in background without the PHP page waiting for it to complete, you could use another (background) PHP script that is "invoked" with wget command. This background PHP script will be executed with privileges, of course, as any other PHP script on your system.
Here is an example on Windows using wget from gnuwin32 packages.
The background code (file test-proc-bg.php) as an exmple ...
sleep(5); // some delay
file_put_contents('test.txt', date('Y-m-d/H:i:s.u')); // writes time in a file
The foreground script, the one invoking ...
$proc_command = "wget.exe http://localhost/test-proc-bg.php -q -O - -b";
$proc = popen($proc_command, "r");
pclose($proc);
You must use the popen/pclose for this to work properly.
The wget options:
-q keeps wget quiet.
-O - outputs to stdout.
-b works on background
Well i found a bit faster and easier version to use
shell_exec('screen -dmS $name_of_screen $command');
and it works.
Here is a function to launch a background process in PHP. Finally created one that actually works on Windows too, after a lot of reading and testing different approaches and parameters.
function LaunchBackgroundProcess($command){
// Run command Asynchroniously (in a separate thread)
if(PHP_OS=='WINNT' || PHP_OS=='WIN32' || PHP_OS=='Windows'){
// Windows
$command = 'start "" '. $command;
} else {
// Linux/UNIX
$command = $command .' /dev/null &';
}
$handle = popen($command, 'r');
if($handle!==false){
pclose($handle);
return true;
} else {
return false;
}
}
Note 1: On windows, do not use /B parameter as suggested elsewhere. It forces process to run the same console window as start command itself, resulting in the process being processed synchronously. To run the process in a separate thread (asynchronously), do not use /B.
Note 2: The empty double quotes after start "" are required if the command is a quoted path. start command interprets the first quoted parameter as window title.
Can you arrange to fork off a separate process, and then run your copy in the background? It's been a while since I did any PHP, but the function pcntl-fork looks promising.
Use this function to run your program in background. It cross-platform and fully customizable.
<?php
function startBackgroundProcess(
$command,
$stdin = null,
$redirectStdout = null,
$redirectStderr = null,
$cwd = null,
$env = null,
$other_options = null
) {
$descriptorspec = array(
1 => is_string($redirectStdout) ? array('file', $redirectStdout, 'w') : array('pipe', 'w'),
2 => is_string($redirectStderr) ? array('file', $redirectStderr, 'w') : array('pipe', 'w'),
);
if (is_string($stdin)) {
$descriptorspec[0] = array('pipe', 'r');
}
$proc = proc_open($command, $descriptorspec, $pipes, $cwd, $env, $other_options);
if (!is_resource($proc)) {
throw new \Exception("Failed to start background process by command: $command");
}
if (is_string($stdin)) {
fwrite($pipes[0], $stdin);
fclose($pipes[0]);
}
if (!is_string($redirectStdout)) {
fclose($pipes[1]);
}
if (!is_string($redirectStderr)) {
fclose($pipes[2]);
}
return $proc;
}
Note that after command started, by default this function closes the stdin and stdout of running process. You can redirect process output into some file via $redirectStdout and $redirectStderr arguments.
Note for windows users:
You cannot redirect stdout/stderr to nul in the following manner:
startBackgroundProcess('ping yandex.com', null, 'nul', 'nul');
However, you can do this:
startBackgroundProcess('ping yandex.com >nul 2>&1');
Notes for *nix users:
1) Use exec shell command if you want get actual PID:
$proc = startBackgroundProcess('exec ping yandex.com -c 15', null, '/dev/null', '/dev/null');
print_r(proc_get_status($proc));
2) Use $stdin argument if you want to pass some data to the input of your program:
startBackgroundProcess('cat > input.txt', "Hello world!\n");
You might try a queuing system like Resque. You then can generate a job, that processes the information and quite fast return with the "processing" image. With this approach you won't know when it is finished though.
This solution is intended for larger scale applications, where you don't want your front machines to do the heavy lifting, so they can process user requests.
Therefore it might or might not work with physical data like files and folders, but for processing more complicated logic or other asynchronous tasks (ie new registrations mails) it is nice to have and very scalable.
A working solution for both Windows and Linux. Find more on My github page.
function run_process($cmd,$outputFile = '/dev/null', $append = false){
$pid=0;
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$cmd = 'wmic process call create "'.$cmd.'" | find "ProcessId"';
$handle = popen("start /B ". $cmd, "r");
$read = fread($handle, 200); //Read the output
$pid=substr($read,strpos($read,'=')+1);
$pid=substr($pid,0,strpos($pid,';') );
$pid = (int)$pid;
pclose($handle); //Close
}else{
$pid = (int)shell_exec(sprintf('%s %s %s 2>&1 & echo $!', $cmd, ($append) ? '>>' : '>', $outputFile));
}
return $pid;
}
function is_process_running($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
//tasklist /FI "PID eq 6480"
$result = shell_exec('tasklist /FI "PID eq '.$pid.'"' );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('ps %d 2>&1', $pid));
if (count(preg_split("/\n/", $result)) > 2 && !preg_match('/ERROR: Process ID out of range/', $result)) {
return true;
}
}
return false;
}
function stop_process($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$result = shell_exec('taskkill /PID '.$pid );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('kill %d 2>&1', $pid));
if (!preg_match('/No such process/', $result)) {
return true;
}
}
}
Thanks to this answer: A perfect tool to run a background process would be Symfony Process Component, which is based on proc_* functions, but it's much easier to use. See its documentation for more information.
Instead of initiating a background process, what about creating a trigger file and having a scheduler like cron or autosys periodically execute a script that looks for and acts on the trigger files? The triggers could contain instructions or even raw commands (better yet, just make it a shell script).
If using PHP there is a much easier way to do this using pcntl_fork:
http://www.php.net/manual/en/function.pcntl-fork.php
I am heavily using fast_cgi_finish_request()
In combination with a closure and register_shutdown_function()
$message ='job executed';
$backgroundJob = function() use ($message) {
//do some work here
echo $message;
}
Then register this closure to be executed before shutdown.
register_shutdown_function($backgroundJob);
Finally when the response was sent to the client you can close the connection to the client and continue working with the PHP process:
fast_cgi_finish_request();
The closure will be executed after fast_cgi_finish_request.
The $message will not be visible at any time. And you can register as much closures as you want, but take care about script execution time.
This will only work if PHP is running as a Fast CGI module (was that right?!)
If you are looking to execute a background process via PHP, pipe the command's output to /dev/null and add & to the end of the command.
exec("bg_process > /dev/null &");
Note that you can not utilize the $output parameter of exec() or else PHP will hang (probably until the process completes).
PHP scripting is not like other desktop application developing language. In desktop application languages we can set daemon threads to run a background process but in PHP a process is occuring when user request for a page. However It is possible to set a background job using server's cron job functionality which php script runs.
For those of us using Windows, look at this:
Reference: http://php.net/manual/en/function.exec.php#43917
I too wrestled with getting a program to run in the background in
Windows while the script continues to execute. This method unlike the
other solutions allows you to start any program minimized, maximized,
or with no window at all. llbra#phpbrasil's solution does work but it
sometimes produces an unwanted window on the desktop when you really
want the task to run hidden.
start Notepad.exe minimized in the background:
<?php
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("notepad.exe", 7, false);
?>
start a shell command invisible in the background:
<?php
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false);
?>
start MSPaint maximized and wait for you to close it before continuing the script:
<?php
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("mspaint.exe", 3, true);
?>
For more info on the Run() method go to:
http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp
Edited URL:
Go to https://technet.microsoft.com/en-us/library/ee156605.aspx instead as the link above no longer exists.
New answer to an old question. Using this library, the following code would spawn an asynchronous/parallel PHPThread to do background work.
Must have pcntl, posix, and socket extensions
Designed for/tested in CLI mode.
EZ code sample:
function threadproc($thread, $param) {
echo "\tI'm a PHPThread. In this example, I was given only one parameter: \"". print_r($param, true) ."\" to work with, but I can accept as many as you'd like!\n";
for ($i = 0; $i < 10; $i++) {
usleep(1000000);
echo "\tPHPThread working, very busy...\n";
}
return "I'm a return value!";
}
$thread_id = phpthread_create($thread, array(), "threadproc", null, array("123456"));
echo "I'm the main thread doing very important work!\n";
for ($n = 0; $n < 5; $n++) {
usleep(1000000);
echo "Main thread...working!\n";
}
echo "\nMain thread done working. Waiting on our PHPThread...\n";
phpthread_join($thread_id, $retval);
echo "\n\nOur PHPThread returned: " . print_r($retval, true) . "!\n";
From PHP official documentation(php.net)
<?php
function execInBackground($cmd) {
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
?>
I know it is a 100 year old post, but anyway, thought it might be useful to someone. You can put an invisible image somewhere on the page pointing to the url that needs to run in the background, like this:
<img src="run-in-background.php" border="0" alt="" width="1" height="1" />