Чи є спосіб використовувати shell_exec, не чекаючи завершення команди?


95

У мене є інтенсивне завдання, яке я хотів би виконати у фоновому режимі.

Користувач натискає сторінку, запускається скрипт PHP, і, нарешті, на основі деяких умов, якщо потрібно, він повинен запустити сценарій оболонки, наприклад:

shell_exec('php measurePerformance.php 47 844 email@yahoo.com');

В даний час я використовую shell_exec , але для цього потрібно, щоб сценарій чекав вихідних даних. Чи є спосіб виконати команду, яку я хочу, не чекаючи її завершення?


ПРИМІТКА: Процес повинен розпочатися негайно, тому cron не є варіантом.
ToughPal

2
Лише коротка примітка: переконайтесь, що сторінка буде доступна не всім (пошукові системи / шахрайські користувачі), і якщо ви перебуваєте у спільному середовищі, час виконання всіх ваших скриптів (зокрема php!), Ймовірно, обмежений. У будь-якому випадку ви можете поглянути на set_time_limit / php.ini.
merkuro

Відповіді:


150

Як щодо додавання.

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

shell_exec('php measurePerformance.php 47 844 email@yahoo.com > /dev/null 2>/dev/null &');

Зауважте, це також позбавляє stdio та stderr.


2
Ні. Побічних ефектів немає. Якщо ви коли-небудь вирішили, що хочете stdio або stderr вивести ваш процес, розгляньте stackoverflow.com/questions/45953/…
джиттер

1
Питання: Це просто відкидання результату, так? PHP все ще чекає завершення процесу, перш ніж продовжувати виконання, або він запускається і забуває?
Алан Сторм

5
Так викидає. Так вогонь і забудь
тремтіння

3
Примітка: > /dev/null 2>&1 &як видно з інших відповідей, це стисла форма, > /dev/null 2>/dev/null &наведена тут. В основному це означає "перенаправити STDERR (2) туди ж, де STDOUT (& 1)".
римо

3
Зазвичай я отримую PID запущеного сценарію, додаючи echo $! >> /tmp/pid.txt в кінці команди exec, але, перенаправивши вивід і помилку на / dev / null, більше не буде pid-файлу: чи може хтось із вас отримати PID сценарію, запущеного exec, не чекаючи вихідних даних?
hugsbrugs

28

Це виконає команду та від’єднається від запущеного процесу. Звичайно, це може бути будь-яка ваша команда. Але для тесту ви можете створити php-файл із командою sleep (20).

exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");

це краще це або shell_exec?
realtebo

привіт, чи можу я запустити функцію за допомогою цього shell_exec ("nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2> & 1 &");
Waseem Bashir

Чому і те, nohup і інше& ?
bugmenot123

11

Ви також можете негайно повернути свої дані клієнту і продовжити обробку коду PHP після цього.

Це метод, який я використовую для довгоочікуваних викликів Ajax, який не матиме жодного ефекту на стороні клієнта:

ob_end_clean();
ignore_user_abort();
ob_start();
header("Connection: close");
echo json_encode($out);
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();
// execute your command here. client will not wait for response, it already has one above.

Детальне пояснення ви можете знайти тут: http://oytun.co/response-now-process-later


1
Опс ... Я прокинув тут зомбі-запитання, я ще не зрозумів. Але ця частина інформації може бути корисною для інших.
Ойтун

3
Це не має нічого спільного з shell_exec
bugmenot123

8

У Windows 2003 для виклику іншого сценарію без очікування я використав це:

$commandString = "start /b c:\\php\\php.EXE C:\\Inetpub\\wwwroot\\mysite.com\\phpforktest.php --passmsg=$testmsg"; 
pclose(popen($commandString, 'r'));

Це працює Тільки ПІСЛЯ надання дозволів на зміну cmd.exe- додайте Читати та Виконувати для IUSR_YOURMACHINE(я також встановив запис на Заборонити).


7

Звичайно, для windowsвас можна використовувати:

$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("C:/path/to/php-win.exe -f C:/path/to/script.php", 0, false);

Примітка:

Якщо з’являється COMпомилка, додайте розширення до свого php.iniі перезапустіть apache:

[COM_DOT_NET]
extension=php_com_dotnet.dll

Я не маю ідеї, але це спрацювало для мене. Будь ласка, поясніть, що таке wscript.shell і що він робить.
GeekWithGlasses

Ви можете пояснити, чому цей рядок не дає жодного результату? `$ oExec = $ WshShell-> Виконати ('C: \ Users \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C: \ xampp \ htdocs \ composer \ test_0.js', 0 , false); `
GeekWithGlasses

Можливо, у вас є помилка на test_0.js, перевірте фантомний журнал.
CONvid19,

6

Використовуйте popenкоманду PHP , наприклад:

pclose(popen("start c:\wamp\bin\php.exe c:\wamp\www\script.php","r"));

Це створить дочірній процес, і сценарій буде виконаний у фоновому режимі, не чекаючи виводу.


4
Це чекає, поки закінчиться процес дитини. Принаймні на Перемогу
Макс Чернопольський

Передустановка тут досягається за допомогою команди Windows "start", яка додає префікс до exe, який ви хочете запустити, він не буде працювати, якщо його опустити, і я б не очікував, що він буде працювати в іншій ОС ... але це РОБИТЬ працює для мене, дякую! :-)
Антоній

1

Якщо це не з веб-сторінки, я рекомендую генерувати якийсь сигнал (можливо, опускаючи файл у каталог) і мати завдання cron, щоб забрати роботу, яку потрібно виконати. В іншому випадку ми, швидше за все, потрапимо на територію використання pcntl_fork()та exec()зсередини процесу Apache, і це просто погано.


1
ти сказав, що це поганий моджо. Ви можете, будь ласка, детальніше розказати?
Mayank

1

Це буде працювати, але вам доведеться бути обережним, щоб не перевантажити ваш сервер, оскільки він створюватиме новий процес кожного разу, коли ви викликаєте цю функцію, яка буде працювати у фоновому режимі. Якщо одночасно здійснюється лише один одночасний дзвінок, тоді цей обхідний спосіб зробить свою роботу.

Якщо ні, то я порадив би запустити чергу повідомлень, наприклад, beanstalkd / gearman / amazon sqs.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.