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

19

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

EDIT:

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

После того, как вы выполните первый ob_flush, вы хотите, чтобы отображался другой вывод? Или вы хотите, чтобы запрос был полностью завершен, насколько клиент может сказать, а затем какая-то обработка продолжалась в фоновом режиме? Corbin
Все, что вам нужно, это flush (), если ваша выходная буферизация уже отключена в php.ini, однако, чтобы это работало, вам нужно настроить Apache, NginX и т. Д. PJ Brunet
Хорошо, обновили мой ответ. Corbin
продолжить в фоновом режиме aWebDeveloper

Ваш Ответ

7   ответов
0

ignore_user_abort(true);
fastcgi_finish_request();

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

-1

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

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, Все они после этого закрыли запрос.

@Zombaya, Почему длина не соответствует фактической длине? Почему он не мог просто сделатьheader("Content-Length: ".strlen($content));
@ Zombaya, я не вижу, насколько это актуально. До тех пор, пока он не пытается отключить вывод после определенного количества, это должно работать для завершения запроса после отправки необходимых данных.
Что ж, когда я попытался сделать это, а длина не соответствовала фактической длине, соединение не всегда закрывалось и продолжало загружаться.
Это работает нормально, но если вы настроили apache для использования gzip-сжатия на ваших выходных веб-страницах, он изменяет содержимое вашего ответа, но не изменяет заголовок content-length-header. У меня были проблемы с этим в прошлом.
Вот почему длина содержимого должна быть такой же длины, что и фактическое содержимое. И остерегайтесь gzip, так как это изменит длину вашего ответа.
16

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

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

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

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

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

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

когда новый пользователь входит в систему, я хочу сохранить много данных. Эти данные должны быть немедленно сохранены, но не прерывать пользователя, т.е. показывать загрузку в браузере aWebDeveloper
16

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');, Но это не будет работать, если вы будете использовать правила перезаписи для перехода на свою страницу, так как это также изменит эти переменные среды. По крайней мере, так оно и было для меня.

Более подробные сведения о сбрасывании вашего контента пользователю вруководство.

Просто для справки PHP-функция ob_get_contentS
Добро пожаловать :)
Найдите преднамеренную ошибку. $ len! = размер $;
@ LukeOliff, спасибо за хедз-ап, изменил его.
0

fastcgi_finish_request

This function flushes all response data to the client and finishes the request. This allows for time consuming tasks to be performed without leaving the connection to the client open.

не работает на Apache. (PHP 5 & gt; = 5.3.3, PHP 7)

2

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

Было бы полезно, если бы вы добавили небольшой фрагмент о том, как это работает, поэтому в случае, если ваш сайт когда-нибудь выйдет из строя, у нас все еще есть ответ. Код, который вы написали в своем блоге, работает. Однако, если вы сказали apache, прежде чем gzip ваш контент, он больше не будет работать (так как длина больше не будет правильной)
4

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, second argument is an array to be passed to 'test' function with an indexed array

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

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