Как запустить PHP-скрипт в фоновом режиме после отправки формы?

15 ответов


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

я использую следующую строку для вызова сценария электронной почты:

shell_exec("/path/to/php /path/to/send_notifications.php '".$post_id."' 'alert' >> /path/to/alert_log/paging.log &");

важно заметить & at конец команды (как указано в @netcoder). Эта команда UNIX запускает процесс в фоновом режиме.

дополнительные переменные, окруженные одинарными кавычками после пути к скрипту, устанавливаются как $_SERVER['argv'] переменные, которые я могу вызвать в своем скрипте.

сценарий электронной почты затем выводит в мой файл журнала с помощью >> и выведет что-то вроде этого:

[2011-01-07 11:01:26] Alert Notifications Sent for http://alerts.illinoisstate.edu/2049 (SCRIPT: 38.71 seconds)
[2011-01-07 11:01:34] CRITICAL ERROR: Alert Notifications NOT sent for http://alerts.illinoisstate.edu/2049 (SCRIPT: 23.12 seconds)

на серверах Linux / Unix вы можете выполнить задание в фоновом режиме с помощью proc_open:

$descriptorspec = array(
   array('pipe', 'r'),               // stdin
   array('file', 'myfile.txt', 'a'), // stdout
   array('pipe', 'w'),               // stderr
);

$proc = proc_open('php email_script.php &', $descriptorspec, $pipes);

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


PHP exec("php script.php") можете сделать это.

С руководство:

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

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


и почему бы не сделать HTTP-запрос в скрипте и не проигнорировать ответ ?

http://php.net/manual/en/function.httprequest-send.php

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


Как насчет этого?

  1. ваш PHP-скрипт, который содержит форму, сохраняет флаг или некоторое значение в базе данных или файле.
  2. второй PHP-скрипт периодически опрашивает это значение, и если оно установлено, он синхронно запускает скрипт электронной почты.

этот второй PHP-скрипт должен быть настроен на запуск как cron.


Как я знаю, вы не можете сделать это простым способом (см. fork exec и т. д. (не работают под windows)), может быть, вы можете изменить подход, использовать фон браузера, публикующего форму в ajax, поэтому, если сообщение все еще работает, у вас нет времени ожидания.
Это может помочь, даже если вам нужно сделать некоторые длительные разработки.

О отправке почты всегда рекомендуется использовать буферизатор, может быть локальным и быстрым SMTP-сервером, который принимает ваши запросы и катушку их в реальный MTA или помещает все в DB, чем использовать cron, который катает очередь.
Cron может быть на другой машине, вызывающей диспетчер очереди очереди как внешний url:

* * * * * wget -O /dev/null http://www.example.com/spooler.php

более простой способ запуска PHP-скрипта в фоновом режиме -

php script.php >/dev/null &

скрипт будет работать в фоновом режиме и страница также попадете на страницу акции быстрее.


фоновое задание звучит как хорошая идея для этого.

вам понадобится доступ ssh к машине для запуска скрипта как cron.

$ php scriptname.php, чтобы запустить его.


если вы можете получить доступ к серверу через ssh и можете запускать свои собственные скрипты, вы можете сделать простой сервер fifo с помощью php (хотя вам придется перекомпилировать php с posix поддержка fork).

сервер может быть написан на чем угодно, вы, вероятно, можете легко сделать это на python.

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

пример сервера :

<?php
define('FIFO_PATH', '/home/user/input.queue');
define('FORK_COUNT', 10);

if(file_exists(FIFO_PATH)) {
    die(FIFO_PATH . ' exists, please delete it and try again.' . "\n");
}

if(!file_exists(FIFO_PATH) && !posix_mkfifo(FIFO_PATH, 0666)){
    die('Couldn\'t create the listening fifo.' . "\n");
}

$pids = array();
$fp = fopen(FIFO_PATH, 'r+');
for($i = 0; $i < FORK_COUNT; ++$i) {
    $pids[$i] = pcntl_fork();
    if(!$pids[$i]) {
        echo "process(" . posix_getpid() . ", id=$i)\n";
        while(true) {
            $line = chop(fgets($fp));
            if($line == 'quit' || $line === false) break;
            echo "processing (" . posix_getpid() . ", id=$i) :: $line\n";
        //  $data = json_decode($line);
        //  processData($data);
        }
        exit();
    }
}
fclose($fp);
foreach($pids as $pid){
    pcntl_waitpid($pid, $status);
}
unlink(FIFO_PATH);
?>

пример клиента :

<?php
define('FIFO_PATH', '/home/user/input.queue');
if(!file_exists(FIFO_PATH)) {
    die(FIFO_PATH . ' doesn\'t exist, please make sure the fifo server is running.' . "\n");
}

function postToQueue($data) {
    $fp = fopen(FIFO_PATH, 'w+');
    stream_set_blocking($fp, false); //don't block
    $data = json_encode($data) . "\n";
    if(fwrite($fp, $data) != strlen($data)) {
        echo "Couldn't the server might be dead or there's a bug somewhere\n";
    }
    fclose($fp);
}
$i = 1000;
while(--$i) {
    postToQueue(array('xx'=>21, 'yy' => array(1,2,3)));
}
?>

предполагая, что вы работаете на платформе * nix, используйте cron и php исполняемый файл.

EDIT:

есть довольно много вопросов, требующих "запуска php без cron"на SO уже. Вот один:

сценарии расписания без использования CRON

тем не менее, ответ exec () выше звучит очень многообещающе:)


если вы на Windows, исследования proc_open или popen...

но если мы находимся на одном сервере "Linux" под управлением cpanel, то это правильный подход:

#!/usr/bin/php 
<?php
$pid = shell_exec("nohup nice php -f            
'path/to/your/script.php' /dev/null 2>&1 & echo $!");
While(exec("ps $pid"))
{ //you can also have a streamer here like fprintf,        
 // or fgets
}
?>

Не используйте fork() или curl если вы сомневаетесь, что можете справиться с ними, это так же, как злоупотреблять вашим сервером

наконец, на script.php файл, который называется выше, обратите внимание на это убедитесь, что вы написали:

<?php
ignore_user_abort(TRUE);
set_time_limit(0);
ob_start();
// <-- really optional but this is pure php

//Code to be tested on background

ob_flush(); flush(); 
//this two do the output process if you need some.        
//then to make all the logic possible


str_repeat(" ",1500); 
//.for progress bars or loading images

sleep(2); //standard limit

?>

из всех ответов ни один не считал смехотворно легким fastcgi_finish_request функция, которая при вызове сбрасывает все оставшиеся выходные данные в браузер и закрывает сеанс Fastcgi и HTTP-соединение, позволяя скрипту работать в фоновом режиме.

пример:

<?php
header('Content-Type: application/json');
echo json_encode(['ok' => true]);
fastcgi_finish_request(); // The user is now disconnected from the script

// do stuff with received data,

в моем случае у меня есть 3 парама, один из них-string (mensaje):

exec("C:\wamp\bin\php\php5.5.12\php.exe C:/test/N/trunk/api/v1/Process.php $idTest2 $idTest3 \"$mensaje\" >> c:/log.log &");

в моем процессе.php у меня есть этот код:

if (!isset($argv[1]) || !isset($argv[2]) || !isset($argv[3]))
{   
    die("Error.");
} 

$idCurso = $argv[1];
$idDestino = $argv[2];
$mensaje = $argv[3];

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

form_action_page.в PHP

     <?php

    post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue");
    //post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue2");
    //post_async("http://localhost/projectname/otherpage.php", "Keywordname=anyValue");
    //call as many as pages you like all pages will run at once //independently without waiting for each page response as asynchronous.

  //your form db insertion or other code goes here do what ever you want //above code will work as background job this line will direct hit before //above lines response     
                ?>
                <?php

                /*
                 * Executes a PHP page asynchronously so the current page does not have to wait for it to     finish running.
                 *  
                 */
                function post_async($url,$params)
                {

                    $post_string = $params;

                    $parts=parse_url($url);

                    $fp = fsockopen($parts['host'],
                        isset($parts['port'])?$parts['port']:80,
                        $errno, $errstr, 30);

                    $out = "GET ".$parts['path']."?$post_string"." HTTP/1.1\r\n";//you can use POST instead of GET if you like
                    $out.= "Host: ".$parts['host']."\r\n";
                    $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
                    $out.= "Content-Length: ".strlen($post_string)."\r\n";
                    $out.= "Connection: Close\r\n\r\n";
                    fwrite($fp, $out);
                    fclose($fp);
                }
                ?>

testpage.в PHP

    <?
    echo $_REQUEST["Keywordname"];//case1 Output > testValue
//here do your background operations it will not halt main page
    ?>

PS:Если вы хотите отправить параметры url как цикл, то следуйте этому ответу:https://stackoverflow.com/a/41225209/6295712


это работает для меня. tyr это

exec(“php asyn.php”.” > /dev/null 2>/dev/null &“);