php wykonuje proces w tle

Muszę wykonać kopię katalogu po akcji użytkownika, ale katalogi są dość duże, więc chciałbym móc wykonać taką akcję bez uświadamiania sobie przez Użytkownika czasu potrzebnego na wykonanie kopii.

Wszelkie sugestie będą mile widziane.

 239
php
Author: tim, 2008-09-05

17 answers

Zakładając, że to działa na komputerze z Linuksem, zawsze radziłem sobie z tym w ten sposób:

exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));

Uruchamia polecenie $cmd, przekierowuje wyjście polecenia do $outputfile i zapisuje ID procesu do $pidfile.

To pozwala łatwo monitorować, co robi proces i czy nadal jest uruchomiony.

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;
}
 333
Author: Mark Biek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-23 08:38:09

Napisz proces jako skrypt po stronie serwera w dowolnym języku (php/bash/perl/etc), a następnie wywołaj go z funkcji sterowania procesem w Twoim skrypcie php.

Funkcja prawdopodobnie wykrywa, czy standardowe io jest używane jako strumień wyjściowy i jeśli jest to wtedy ustawia wartość zwracaną..if not then it ends

Proc_Close (Proc_Open ("./command --foo=1 &", Array (), $foo));

Przetestowałem to szybko z linii poleceń używając" sleep 25s " jako polecenia i działało jak urok.

(odpowiedź znaleziona tutaj )

 23
Author: Eric Goodwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-05 15:13:54

Chciałbym tylko dodać bardzo prosty przykład testowania tej funkcjonalności w systemie Windows:

Utwórz dwa następujące pliki i zapisz je w katalogu www:

Pierwszy plan.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>";
?>

Tło.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);
?>

Daj uprawnienia IUSR do zapisu do katalogu, w którym utworzyłeś powyższe pliki

Dać IUSR uprawnienia do odczytu i wykonania C:\Windows\System32\cmd.exe

Uderz w pierwszy plan.php z przeglądarki internetowej

Należy: renderowane do przeglądarki z bieżącymi znacznikami czasu i lokalnym zasobem # w tablicy wyjściowej:

loading page
calling run_background_process
  foreground start time = 1266003600
  foreground end time = 1266003600
output = Array
(
    [0] => 15010
)
end of page

Powinieneś zobaczyć testoutput.php w tym samym katalogu co powyższe pliki zostały zapisane i powinno być puste

Powinieneś zobaczyć testprocesses.php w tym samym katalogu co powyższe pliki zostały zapisane i powinno zawierać następujący tekst z bieżącymi znacznikami czasu:

foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610
 19
Author: Captain Obvious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-12 20:40:50

Możesz spróbować dołączyć to do komendy

>/dev/null 2>/dev/null &

Np.

shell_exec('service named reload >/dev/null 2>/dev/null &');
 18
Author: wlf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-14 17:18:07

Jeśli musisz zrobić coś w tle bez strony PHP czekającej na jej zakończenie, możesz użyć innego (tła) skryptu PHP, który jest "wywoływany" za pomocą polecenia wget. Ten skrypt PHP w tle będzie oczywiście uruchamiany z uprawnieniami, jak każdy inny skrypt PHP w Twoim systemie.

Oto przykład na Windows używający wget z pakietów gnuwin32.

Kod tła (plik test-proc-bg.php) jako exmple ...

sleep(5);   // some delay
file_put_contents('test.txt', date('Y-m-d/H:i:s.u')); // writes time in a file

Scenariusz pierwszoplanowy, ten / align = "left" / ..

$proc_command = "wget.exe http://localhost/test-proc-bg.php -q -O - -b";
$proc = popen($proc_command, "r");
pclose($proc);

Musisz użyć popen / pclose, aby to działało poprawnie.

Opcje wget:

-q    keeps wget quiet.
-O -  outputs to stdout.
-b    works on background
 11
Author: Neven Boyanov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-22 06:06:51

Cóż znalazłem nieco szybszą i łatwiejszą wersję w użyciu

shell_exec('screen -dmS $name_of_screen $command'); 
I działa.
 7
Author: Morfidon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-03 21:34:18

Oto funkcja do uruchomienia procesu w tle w PHP. W końcu stworzyłem taki, który faktycznie działa również na Windows, po wielu czytaniach i testowaniu różnych podejść i parametrów.

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;
  }
}

Uwaga 1: w systemie windows nie używaj parametru /B, jak sugerowano w innym miejscu. Zmusza proces do uruchomienia tego samego okna konsoli co polecenie start, co powoduje, że proces jest przetwarzany synchronicznie. Aby uruchomić proces w osobnym wątku (asynchronicznie), nie używaj /B.

Uwaga 2: puste podwójne cudzysłowy po {[4] } są wymagane, jeśli polecenie jest cytowaną ścieżką. start polecenie interpretuje pierwszy cytowany parametr jako tytuł okna.

 6
Author: Alph.Dev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-05 13:31:19

Czy możesz zaaranżować oddzielny proces, a następnie uruchomić kopię w tle? Dawno nie robiłem żadnego PHP, ale funkcja pcntl-fork wygląda obiecująco.

 4
Author: Matt Sheppard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-05 14:49:09

Możesz spróbować systemu kolejkowego jak Resque . Następnie można wygenerować zadanie, które przetwarza informacje i dość szybki powrót z" przetwarzania " obrazu. Dzięki temu podejściu nie będziesz wiedział, kiedy to się skończy.

To rozwiązanie jest przeznaczone do zastosowań na większą skalę, gdzie nie chcesz, aby Twoje przednie maszyny wykonywały ciężkie podnoszenie, aby mogły przetwarzać żądania użytkowników. Dlatego może lub nie może działać z danymi fizycznymi, takimi jak pliki i foldery, ale dla przetwarzanie bardziej skomplikowanej logiki lub innych zadań asynchronicznych (np. nowe rejestracje) jest przyjemne i bardzo skalowalne.

 4
Author: scones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-02 16:12:14

Użyj tej funkcji, aby uruchomić program w tle. Jest wieloplatformowy i w pełni konfigurowalny.

<?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;
}

Zauważ, że po uruchomieniu polecenia, domyślnie ta funkcja zamyka stdin i stdout uruchomionego procesu. Możesz przekierować wyjście procesu do jakiegoś pliku za pomocą argumentów $redirectStdout i $redirectStderr.

Uwaga dla użytkowników systemu windows: nie ma możliwości przekierowania stdout/stderr na urządzenie nul. Niestety nie możesz tego zrobić:

startBackgroundProcess('ping yandex.com', null, 'nul', 'nul');

Więc powinieneś przekierowanie stderr/stdin do poprawnego pliku lub polecenie powinno oczekiwać, że nie jest deskryptorem stderr/stdout.

Uwagi dla użytkowników *nix:

1) Użyj polecenia powłoki Exec, jeśli chcesz uzyskać rzeczywisty PID:

$proc = startBackgroundProcess('exec ping yandex.com -c 15', null, '/dev/null', '/dev/null');
print_r(proc_get_status($proc));

2) użyj argumentu $stdin, jeśli chcesz przekazać niektóre dane do wejścia programu:

startBackgroundProcess('cat > input.txt', "Hello world!\n");
 3
Author: Pascal9x,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-04 08:35:03

Zamiast inicjować proces w tle, co powiesz na utworzenie pliku wyzwalacza i okresowe uruchamianie skryptu, który szuka i działa na plikach wyzwalaczy? Wyzwalacze mogą zawierać instrukcje lub nawet surowe polecenia (jeszcze lepiej, po prostu zrobić z niego skrypt powłoki).

 2
Author: Brian Warshaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-26 11:22:37

Jeśli używasz PHP, jest o wiele łatwiejszy sposób, aby to zrobić używając pcntl_fork:

Http://www.php.net/manual/en/function.pcntl-fork.php

 2
Author: John Foley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-02 15:40:07

Mocno używam fast_cgi_finish_request()

W połączeniu z zamknięciem i register_shutdown_function ()

$message ='job executed';
$backgroundJob = function() use ($message) {
     //do some work here
    echo $message;
}

Następnie zarejestruj to zamknięcie, aby zostało wykonane przed zamknięciem.

register_shutdown_function($backgroundJob);
W końcu po wysłaniu odpowiedzi do klienta możesz zamknąć połączenie z klientem i kontynuować pracę z procesem PHP:
fast_cgi_finish_request();

Zamknięcie zostanie wykonane po fast_cgi_finish_request.

Wiadomość $nie będzie widoczna w żadnym momencie. I możesz zarejestrować się jako wiele zamknięć, jak chcesz, ale dbać o czas wykonania skryptu. To zadziała tylko wtedy, gdy PHP działa jako Szybki moduł CGI(tak było?!)

 2
Author: sgotre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-02 23:00:40

Działające rozwiązanie zarówno dla Windows, jak i Linuksa. Dowiedz się więcej na Moja strona github .

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;
                        }
                    }
            }
 2
Author: Joshy Francis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-07 05:50:08

Skrypty PHP nie są podobne do innych języków programistycznych. W językach aplikacji desktopowych możemy ustawić wątki demona, aby uruchamiał proces w tle, ale w PHP proces zachodzi, gdy użytkownik żąda strony. Możliwe jest jednak ustawienie zadania w tle za pomocą funkcji Zadania cron serwera, którą uruchamia skrypt php.

 1
Author: shihab mm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-03 12:50:32

Dla tych z nas, którzy używają Windows, spójrz na to:

Odniesienie: http://php.net/manual/en/function.exec.php#43917

Ja też miałem problem z uruchomieniem programu w tle w Windows podczas wykonywania skryptu. Metoda ta w przeciwieństwie do inne rozwiązania pozwalają uruchomić dowolny program zminimalizowany, zmaksymalizowany, albo bez okna. llbra @ phpbrasil rozwiązanie działa ale to czasami tworzy niechciane okno na pulpit kiedy naprawdę chcesz, aby zadanie było ukryte.

Start Notatnik.exe zminimalizowane w tle:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("notepad.exe", 7, false); 
?> 

Uruchom polecenie powłoki niewidoczne w tle:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false); 
?> 

Uruchom mspaint i poczekaj, aż go zamkniesz przed kontynuowaniem skryptu:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("mspaint.exe", 3, true); 
?> 

Aby uzyskać więcej informacji na temat metody Run () Przejdź do: http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp

Edytowany URL:

Idź do https://technet.microsoft.com/en-us/library/ee156605.aspx zamiast tego, ponieważ powyższy link już nie istnieje.

 1
Author: Jimmy Ilenloa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-30 21:02:55

Wiem, że to 100-letni post, ale w każdym razie pomyślałem, że może się komuś przydać. Możesz umieścić niewidoczny obraz gdzieś na stronie wskazującej adres url, który musi być uruchomiony w tle, w ten sposób:

<img src="run-in-background.php" border="0" alt="" width="1" height="1" />

 -6
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-11 19:41:03