Как я закрываю соединение рано?

Я пытаюсь сделать вызов Ajax (с помощью JQuery), который будет инициировать довольно долгий процесс. Я хотел бы, чтобы сценарий просто отправил ответ, указывающий, что процесс запустился, но JQuery не возвратит ответ, пока Сценарий PHP не будет сделан, работая.

Я попробовал это "близким" заголовком (ниже), и также выходной буферизацией; ни один, кажется, не работает. Какие-либо предположения? или это - что-то, что я должен сделать в JQuery?

<?php

echo( "We'll email you as soon as this is done." );

header( "Connection: Close" );

// do some stuff that will take a while

mail( 'dude@thatplace.com', "okay I'm done", 'Yup, all done.' );

?>
96
задан FluorescentGreen5 20 July 2019 в 11:56
поделиться

7 ответов

Следующая страница руководства PHP (включая пользовательские примечания) предлагает многоадресные команды о том, как закрыть соединение TCP к браузеру, не заканчивая Сценарий PHP:

, Предположительно, это требует немного больше, чем отправка близкого заголовка.

<час>

OP тогда подтверждает: да, это добилось цели: указывающий на пользовательское примечание № 71172 (ноябрь 2006) скопированный здесь:

Закрытие пользовательского соединения браузера при поддерживании сценария PHP в рабочем состоянии было проблемой начиная с [PHP] 4.1, когда поведение register_shutdown_function() было изменено так, чтобы это автоматически не закрывало пользовательское соединение.

sts в почтовой точке xubion отмечают точкой hu, Отправил исходное решение:

<?php
header("Connection: close");
ob_start();
phpinfo();
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush();
flush();
sleep(13);
error_log("do something in the background");
?>

, Который хорошо работает, пока Вы не занимаете место phpinfo() echo('text I want user to see');, в этом случае, заголовки никогда не отправляются!

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

<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(true); // just to be safe
ob_start();
echo('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
// Do processing here 
sleep(30);
echo('Text user will never see');
?>

Просто провел 3 часа, пытаясь понять этого, надеяться, что это помогает кому-то:)

Протестированный в:

  • IE 7.5730.11
  • <час> Mozilla Firefox 1.81

Позже в июле 2010 в связанный ответ арктический Огонь тогда связал два дальнейших пользовательских примечания что were-follow-ups к тому выше:

85
ответ дан Community 24 November 2019 в 05:37
поделиться

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

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

0
ответ дан Ole Helgesen 24 November 2019 в 05:37
поделиться

Хорошо, таким образом, в основном способ, которым jQuery делает запрос XHR, даже ob_flush метод, не будет работать, потому что Вы неспособны работать, функция на каждом onreadystatechange. jQuery проверяет состояние, затем выбирает надлежащие действия для взятия (завершенный, ошибка, успех, тайм-аут). И хотя я был неспособен найти ссылку, я вспоминаю слушание, что это не работает со всеми реализациями XHR. Метод, которому я верю, должен работать на Вас, пересечение опрос навсегда-кадра и ob_flush.

<?php
 function wrap($str)
 {
  return "<script>{$str}</script>";
 };

 ob_start(); // begin buffering output
 echo wrap("console.log('test1');");
 ob_flush(); // push current buffer
 flush(); // this flush actually pushed to the browser
 $t = time();
 while($t > (time() - 3)) {} // wait 3 seconds
 echo wrap("console.log('test2');");
?>

<html>
 <body>
  <iframe src="ob.php"></iframe>
 </body>
</html>

И потому что сценарии выполняются встроенные, поскольку буферы сбрасываются, Вы получаете выполнение. Для создания этого полезным измените console.log на метод обратного вызова, определенный в Вас основная установка сценария, чтобы получить данные и действовать на него. Надежда это помогает. С наилучшими пожеланиями, Morgan.

0
ответ дан Morgan ARR Allen 24 November 2019 в 05:37
поделиться

Ваша проблема может быть решена путем выполнения некоторого параллельного программирования в php. Я задал вопрос об этом несколько недель назад здесь: , Как можно использовать много поточную обработку в приложениях PHP

И получил большие ответы. Мне понравился тот в особенности очень. Писатель сделал ссылку на Легкая Параллельная обработка в PHP (сентябрь 2008; johnlim) учебное руководство , которое может на самом деле решить Вашу проблему очень хорошо, поскольку я использовал его уже для контакта с подобной проблемой, которая подошла несколько дней назад.

1
ответ дан Community 24 November 2019 в 05:37
поделиться

Вы могли попытаться сделать многопоточность.

Вы могли сделать на скорую руку сценарий, который делает системный вызов (использующий shell_exec), который называет php двоичный файл со сценарием, чтобы сделать Вашу работу как параметр. Но я не думаю, что это - самый безопасный путь. Возможно, Вы можете материал thighten chrooting процесс php и другой материал

, С другой стороны, существует класс в phpclasses, которые делают тот http://www.phpclasses.org/browse/package/3953.html . Но я не знаю специфических особенностей реализации

2
ответ дан paan 24 November 2019 в 05:37
поделиться

Принятие Вас имеет сервер Linux и корневой доступ, пробует это. Это - простое решение, которое я нашел.

Создают новый каталог для следующих файлов и дают ему полные полномочия. (Мы можем сделать его более безопасным позже.)

mkdir test
chmod -R 777 test
cd test

Помещенный это в файл, названный bgping.

echo starting bgping
ping -c 15 www.google.com > dump.txt &
echo ending bgping

Примечание &. Команда ping будет работать в фоновом режиме, в то время как текущий процесс идет дальше к команде эха. Это проверит с помощью ping-запросов www.google.com 15 раз, который займет приблизительно 15 секунд.

Делают его исполняемым файлом.

chmod 777 bgping

Помещенный это в файл, названный bgtest.php.

<?php

echo "start bgtest.php\n";
exec('./bgping', $output, $result)."\n";
echo "output:".print_r($output,true)."\n";
echo "result:".print_r($result,true)."\n";
echo "end bgtest.php\n";

?>

, Когда Вы запрашиваете bgtest.php в своем браузере, необходимо получить следующий ответ быстро, не ожидая приблизительно 15 секунд команды ping для завершения.

start bgtest.php
output:Array
(
    [0] => starting bgping
    [1] => ending bgping
)

result:0
end bgtest.php

команда ping должна теперь работать на сервере. Вместо команды ping Вы могли выполнить Сценарий PHP:

php -n -f largejob.php > dump.txt &

Hope это помогает!

4
ответ дан Liam 24 November 2019 в 05:37
поделиться

Необходимо отправить эти 2 заголовка:

Connection: close
Content-Length: n (n = size of output in bytes )

Поскольку вам нужно знать размер вашего вывода, вы ' Вам нужно будет буферизовать ваш вывод, а затем передать его в браузер:

// buffer all upcoming output
ob_start();
echo "We'll email you as soon as this is done.";

// get the size of the output
$size = ob_get_length();

// send headers to tell the browser to close the connection
header("Content-Length: $size");
header('Connection: close');

// flush all output
ob_end_flush();
ob_flush();
flush();

// if you're using sessions, this prevents subsequent requests
// from hanging while the background process executes
if (session_id()) session_write_close();

/******** background process starts here ********/

Кроме того, если ваш веб-сервер использует автоматическое сжатие gzip для вывода (например, Apache с mod_deflate), это не сработает, потому что фактический размер вывода изменяется, и Content-Length больше не является точным. Отключите сжатие gzip для конкретного скрипта.

Подробнее см. посетите http://www.zulius.com/how-to/close-browser-connection-continue-execution

54
ответ дан 24 November 2019 в 05:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: