PHP выполнить фоновый процесс - PullRequest
       84

PHP выполнить фоновый процесс

241 голосов
/ 05 сентября 2008

Мне нужно выполнить копию каталога при действии пользователя, но каталоги достаточно велики, поэтому я хотел бы иметь возможность выполнять такое действие, не зная, сколько времени потребуется пользователю для завершения копирования.

Любые предложения будут высоко оценены.

Ответы [ 18 ]

342 голосов
/ 05 сентября 2008

Предполагая, что это работает на машине Linux, я всегда обрабатывал это так:

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

Запускает команду $cmd, перенаправляет вывод команды на $outputfile и записывает идентификатор процесса в $pidfile.

Это позволяет легко отслеживать, что делает процесс и работает ли он до сих пор.

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;
}
22 голосов
/ 05 сентября 2008

Напишите процесс как серверный скрипт на любом удобном для вас языке (php / bash / perl / etc) и затем вызовите его из функций управления процессом в вашем php-скрипте.

Функция, вероятно, обнаруживает, используется ли стандартный поток ввода-вывода в качестве выходного потока, и если это так, тогда будет установлено возвращаемое значение ... если нет, то оно заканчивается

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

Я быстро проверил это из командной строки, используя "sleep 25s" в качестве команды, и это сработало как шарм.

( Ответ найден здесь )

19 голосов
/ 14 августа 2012

Возможно, вы захотите добавить это к своей команде

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

например.

shell_exec('service named reload >/dev/null 2>/dev/null &');
18 голосов
/ 12 февраля 2010

Я просто хотел бы добавить очень простой пример для тестирования этой функциональности в Windows:

Создайте следующие два файла и сохраните их в веб-каталоге:

foreground.php:

<code><?php

ini_set("display_errors",1);
error_reporting(E_ALL);

echo "<pre>loading page
"; функция run_background_process () { file_put_contents ("testprocesses.php", "время начала переднего плана =". time (). "\ n"); echo "
  foreground start time = " . time() . "
"; // вывод команды должен быть перенаправлен в файл или другой поток вывода // http://ca.php.net/manual/en/function.exec.php exec ("php background.php> testoutput.php 2> & 1 & echo $!", $ output); echo "
  foreground end time = " . time() . "
"; file_put_contents ("testprocesses.php", "время окончания переднего плана =". time (). "\ n", FILE_APPEND); вернуть $ output; } echo "
calling run_background_process
"; $ output = run_background_process (); echo "
output = "; print_r($output); echo "
"; echo "
end of page
"; ?>

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

Дайте IUSR разрешение на запись в каталог, в котором вы создали вышеуказанные файлы

Предоставьте разрешение IUSR для чтения и выполнения C: \ Windows \ System32 \ cmd.exe

Хит foreground.php из веб-браузера

Следующее должно быть отображено в браузере с текущими временными метками и локальным ресурсом # в выходном массиве:

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

Вы должны увидеть testoutput.php в том же каталоге, в котором были сохранены вышеуказанные файлы, и он должен быть пустым

Вы должны увидеть testprocesses.php в том же каталоге, в котором были сохранены вышеуказанные файлы, и он должен содержать следующий текст с текущими временными метками:

foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610
10 голосов
/ 28 января 2011

Если вам нужно просто что-то сделать в фоновом режиме, пока страница PHP не ожидает его завершения, вы можете использовать другой (фоновый) скрипт PHP, который «вызывается» с помощью команды wget. Этот фоновый PHP-скрипт будет выполняться с привилегиями, как и любой другой PHP-скрипт в вашей системе.

Вот пример для Windows, использующий wget из пакетов gnuwin32.

Фоновый код (файл test-proc-bg.php) в качестве примера ...

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

Скрипт переднего плана, вызывающий ...

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

Вы должны использовать popen / pclose для правильной работы.

Опции wget:

-q    keeps wget quiet.
-O -  outputs to stdout.
-b    works on background
6 голосов
/ 05 января 2016

Вот функция для запуска фонового процесса в PHP. Наконец, создал тот, который на самом деле работает и в Windows, после длительного чтения и тестирования различных подходов и параметров.

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

Примечание 1: В окнах не используйте параметр /B, как предлагается в другом месте. Это заставляет процесс запускать то же самое окно консоли, что и сама команда start, в результате чего процесс обрабатывается синхронно. Чтобы запустить процесс в отдельном потоке (асинхронно), не используйте /B.

Примечание 2: Пустые двойные кавычки после start "" требуются, если команда является путем в кавычках. Команда start интерпретирует первый цитируемый параметр как заголовок окна.

6 голосов
/ 04 июня 2014

Ну, я нашел более быструю и простую версию для использования

shell_exec('screen -dmS $name_of_screen $command'); 

и все работает.

4 голосов
/ 05 сентября 2008

Можете ли вы организовать отдельный процесс, а затем запустить свою копию в фоновом режиме? Прошло много времени с тех пор, как я написал PHP, но функция pcntl-fork выглядит многообещающе.

3 голосов
/ 15 февраля 2013

Вы можете попробовать систему очередей, такую ​​как Resque . Затем вы можете сгенерировать задание, которое обрабатывает информацию и довольно быстро возвращается с «обработкой» изображения. При таком подходе вы не узнаете, когда он закончится.

Это решение предназначено для более масштабных приложений, когда вы не хотите, чтобы ваши передние машины выполняли тяжелую работу, чтобы они могли обрабатывать запросы пользователей. Поэтому он может работать или не работать с физическими данными, такими как файлы и папки, но для обработки более сложной логики или других асинхронных задач (например, новых почтовых сообщений регистрации) его приятно иметь и очень масштабируемый.

2 голосов
/ 07 октября 2017

Рабочее решение для Windows и Linux. Подробнее на Моя страница 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;
                        }
                    }
            }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...