Проблема в том, что при длительном процессе PHP-скрипт продолжает выполнять, подключен ли клиентский браузер или нет. Есть ли вероятность, что если клиент завершил вызов Ajax сценарию, то скрипт также прекратится на сервере?
Как указано @metadings, php имеет функцию проверки прерывания соединения с именем connection_aborted (). Он вернет 1, если соединение будет завершено иначе 0.
При длительном процессе на стороне сервера пользователю может потребоваться узнать, отсоединен ли клиент от сервера или закрыл браузер, а затем сервер может безопасно завершить процесс.
Особенно в случае, когда приложение использует сеансы php, и если мы оставим длительный процесс, даже после того, как клиент будет отключен, сервер будет не отвечать на этот сеанс. И любой другой запрос от одного и того же клиента будет ждать завершения предыдущего процесса. Причиной этой ситуации является то, что файл сеанса блокируется при запуске процесса. Однако вы можете запрограммировать метод session_write_close (), чтобы разблокировать его. Но это не представляется возможным во всех сценариях, возможно, нужно написать что-то в сеанс в конце процесса.
Теперь, если мы только вызываем connection_aborted () в цикле, тогда он всегда будет возвращать 0, будет ли соединение закрыто или нет.
0 означает, что соединение не прерывается. Это вводит в заблуждение. Однако после повторного поиска и экспериментов, если обнаружили, что выходным буфером в php является причина.
Прежде всего, чтобы проверить прерывания, разработчик в цикле должен отправить некоторый вывод клиенту, повторив некоторый текст. Например:
print " ";
По мере того как процесс все еще выполняется, вывод не будет отправлен клиенту. Теперь для отправки вывода нам необходимо очистить выходной буфер.
flush (); ob_flush ();
И тогда, если мы проверим на прерывания, то он даст правильные результаты.
if (connection_aborted () != 0) { die(); }
Ниже приведен рабочий пример: это будет работать, даже если вы используете PHP-сессию:
session_start (); ignore_user_abort ( TRUE ); file_put_contents ( "con-status.txt", "Process started..\n\n" ); for($i = 1; $i <= 15; $i ++) { print " "; file_put_contents ( "con-status.txt", "Running process unit $i \n", FILE_APPEND ); sleep ( 1 ); // Send output to client flush (); ob_flush (); // Check for connection abort if (connection_aborted () != 0) { file_put_contents ( "con-status.txt", "\nUser terminated the process", FILE_APPEND ); die (); } } file_put_contents ( "con-status.txt", "\nAll units completed.", FILE_APPEND );
EDIT 07-APR-2017
Если кто-то использует Fast-Cgi в Windows, он может фактически прекратить поток CGI из памяти, когда соединение прерывается с использованием следующего кода:
if (connection_aborted () != 0) { apache_child_terminate(); exit; }
Проверьте функцию PHP connection_aborted (). Выполняя обработку, вы можете иногда проверять отмененное соединение, чтобы изящно отменить ход, как это было бы в интерактивной модели потоковой передачи.
Один из способов, который я нашел, который является самым простым способом справиться с этой проблемой тайм-аута, таков:
1: установите значение на сервере как «обработка». Начните независимый поток, чтобы выполнить обработку.
2: Исходный вызов ajax возвращает успех
3: javascript на странице переходит в режим ожидания, который отправляет новый запрос ajax каждые 10 или 30 или 60 секунд или пять или десять минут или что угодно (в зависимости от вашей ситуации), чтобы узнать, сохраняется ли значение на сервере установлено значение «обработка».
4: Независимый поток завершается. Он устанавливает значение на сервере «done».
5: javascript на странице делает свой следующий запрос в режиме ожидания и возвращает «done» и соответствующие данные.
4b: Если нечеткое количество времени проходит без «сделанного», оно регистрируется как сбой. Сколько времени непристойно зависит от вашей ситуации. Отправьте вызов ajax, обновив значение с 'processing' до 'cancel'. 5b: независимый поток периодически проверяет состояние, чтобы убедиться, что он все еще настроен на «обработку». Если он видит сдвиг режима в «cancel», он отменяет себя.
Это то, что вы ищете: http://php.net/manual/en/function.ignore-user-abort.php
Остановка сценария в середине выполнения может привести к неожиданным результатам, поэтому предостережение emptor