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);The
&являясь важным элементом здесь. Сценарий будет продолжен, даже если исходный сценарий закончился.
PHP
exec("php script.php")можете сделать это.С руководство:
Если программа запускается с этого функция, для того чтобы она продолжалась работает в фоновом режиме, вывод программы должны быть перенаправлены на файл или другой поток. Недостаток для этого PHP будет висеть до тех пор, пока выполнение программы заканчивается.
поэтому, если вы перенаправите вывод в файл журнала (что в любом случае является хорошей идеей), ваш вызов скрипта не будет висеть, и ваш скрипт электронной почты будет работать в bg.
а почему бы не сделать HTTP запрос на скрипт и не проигнорировать ответ ?
http://php.net/manual/en/function.httprequest-send.php
Если вы сделаете запрос на скрипт, который вам нужно вызвать, ваш веб-сервер будет работать в фоновом режиме, и вы можете (в своем основном скрипте) показать сообщение, сообщающее пользователю, что скрипт запущен.
Как насчет этого?
- ваш PHP-скрипт, который содержит форму, сохраняет флаг или некоторое значение в базе данных или файле.
- второй PHP-скрипт периодически опрашивает это значение, и если оно установлено, он запускает скрипт электронной почты синхронно.
этот второй PHP-скрипт должен быть настроен на работу как cron.
Как я знаю, вы не можете сделать это простым способом (см. fork exec и т. д. (не работает под windows)), возможно, вы можете изменить подход, использовать фон браузера, отправляющего форму в ajax, поэтому, если сообщение все еще работает, у вас нет времени ожидания.
Это может помочь, даже если вам придется сделать некоторые длительные разработки.
О отправке почты всегда рекомендуется использовать буферизатор, может быть локальный и быстрый smtp-сервер, который принимает ваши запросы и катушку их в реальный MTA или положить все в a DB, чем использовать cron, который катушка очереди.
Cron может быть на другой машине, вызывающей диспетчер очереди как внешний url:* * * * * wget -O /dev/null http://www.example.com/spooler.php
более простой способ запуска PHP-скрипта в фоновом режиме-это
php script.php >/dev/null &скрипт будет работать в фоновом режиме и страница также попадете на страницу акции быстрее.
фоновая работа cron звучит как хорошая идея для этого.
вам понадобится 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
Comments