Как сбросить данные в браузер, но продолжить выполнение


У меня есть ob_start() и соответствующий ob_flush(). Я хотел бы удалить часть данных и продолжить выполнение остальных. Использование ob_flush() не помогло. Также, если возможно, отдых должен происходить без отображения загрузки в браузере.

РЕДАКТИРОВАТЬ:

Я не хочу использовать ajax

Author: Ben Everard, 2012-05-14

7 answers

ob_flush записывает буфер. Другими словами, ob_flush говорит PHP выдать Apache (или nginx/lighttpd/что угодно) выходные данные, а затем PHP должен забыть об этом. Как только Apache получит результат, он сделает с ним все, что захочет. (Другими словами, после ob_flush вы не можете контролировать, будет ли он немедленно записан в браузер или нет).

Итак, короткий ответ: нет гарантированного способа сделать это.

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

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

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

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

 16
Author: Corbin, 2017-12-09 18:33:06

Я делал это в прошлом, и вот как я решил эту проблему:

ob_start();

/*
 * Generate your output here
 */ 

// Ignore connection-closing by the client/user
ignore_user_abort(true);

// Set your timelimit to a length long enough for your script to run, 
// but not so long it will bog down your server in case multiple versions run 
// or this script get's in an endless loop.
if ( 
     !ini_get('safe_mode') 
     && strpos(ini_get('disable_functions'), 'set_time_limit') === FALSE 
){
    set_time_limit(60);
}

// Get your output and send it to the client
$content = ob_get_contents();         // Get the content of the output buffer
ob_end_clean();                      // Close current output buffer
$len = strlen($content);             // Get the length
header('Connection: close');         // Tell the client to close connection
header("Content-Length: $len");     // Close connection after $len characters
echo $content;                       // Output content
flush();                             // Force php-output-cache to flush to browser.
                                     // See caveats below.

// Optional: kill all other output buffering
while (ob_get_level() > 0) {
    ob_end_clean();
}

Как я уже говорил в нескольких комментариях ранее, вам следует следить за тем, чтобы ваш контент не загружался, так как это изменит длину вашего контента, но не изменит заголовок об этом. Он также может буферизировать ваш вывод, поэтому он не будет отправлен клиенту мгновенно.
Вы можете попробовать сообщить apache, чтобы он не архивировал ваш контент, используя apache_setenv('no-gzip', '1');. Но это не сработает, если вы используете правила перезаписи для перехода на свою страницу, так как затем он также изменит эти переменные среды. По крайней мере, для меня это было так.

Смотрите дополнительные предостережения о передаче вашего контента пользователю в руководстве .

 16
Author: Zombaya, 2015-05-13 14:25:11

Это моя функция

function bg_process($fn, $arr) {
    $call = function($fn, $arr){
        header('Connection: close');
        header('Content-length: '.ob_get_length());
        ob_flush();
        flush();
        call_user_func_array($fn, $arr);
        };
    register_shutdown_function($call, $fn, $arr);
    }

Завершите функцию, которая будет выполнена в конце, после того, как php закроет соединение. и, конечно же, браузер прекратит буферизацию.

function test() {
    while (true) {
        echo 'this text will never seen by user';
        }
    }

Вот как вызвать функцию

bg_process('test'); 

Первый аргумент - это callable, второй аргумент - это массив, который должен быть передан функции 'test' с индексированным массивом

Примечание: Я не использую ob_start() в начале сценария.

 4
Author: Afrig Aminuddin, 2012-05-17 06:43:01

У меня есть статья, объясняющая, как этого можно достичь с помощью apache/mod_php в моем блоге здесь: http://codehackit .blogspot.com/2011/07/how-to-kill-http-connection-and.html Надеюсь, это поможет, ура

 2
Author: smassey, 2012-05-14 07:50:34

fastcgi_finish_request

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

Не работает на Apache.(PHP 5>=5.3.3, PHP 7)

 0
Author: sun, 2018-05-25 00:31:47

Если вы используете PHP-FPM:

ignore_user_abort(true);
fastcgi_finish_request();

Вышеуказанные две функции являются ключевыми факторами, которые ignore_user_abort предотвращают ошибку и fastcgi_finish_request закрывают клиентское соединение.

 0
Author: Nick Tsai, 2018-07-28 08:37:02

Использование:

header("Content-Length: $len");

..где $len - длина данных, которые должны быть переданы клиенту.

У меня нет опыта, чтобы знать, когда и где это будет работать, но я попробовал несколько браузеров, и все они мгновенно вернулись с:

<?PHP 
    header("Content-length:5");
    echo "this is more than 5";
    sleep(5);
?>

Редактировать: Chrome, IE и Opera показали this, в то время как FireFox показал this is more than 5. Однако после этого все они закрыли запрос.

 -1
Author: mowwwalker, 2012-05-14 07:58:22