2012-01-23 14 views
6

Czy można zamknąć strumień wyjściowy skryptu PHP? Mam skrypt, który musi wykonać pewne przetwarzanie, ale w trakcie i po zakończeniu przetwarzania nie będzie już wysyłał żadnych danych do klienta, dlatego chciałbym zamknąć połączenie przed przetwarzaniem.PHP: zamknij strumień wyjściowy

Edytuj: W mojej aplikacji mam pamięć podręczną, która musi być odświeżana co jakiś czas. Jednak nie chcę spowalniać użytkownika. Chcę na końcu skryptu określić, czy pamięć podręczna musi zostać odbudowana. Dlatego najpierw chcę zamknąć strumień wyjściowy, aby użytkownik uzyskał dane, a następnie chciałby odbudować pamięć podręczną. Nie jest to naprawdę ważne, ale myślę, że lepiej najpierw zamknąć połączenie, aby użytkownik nie zauważył, że pamięć podręczna jest odbudowywana, jeśli zajmuje to dużo czasu.

+0

Dlaczego trzeba to zrobić? Czy możesz opublikować trochę kodu, aby pomóc nam zrozumieć trochę więcej? –

+0

+1 do tego, co powiedział Jonathan. Powiedz nam coś więcej o tym, dlaczego chcesz to zrobić. –

Odpowiedz

4

UPDATE

Sposób obsługi tej obudowie jest połączenie buforowania wyjściowego i odpowiednie nagłówki HTTP.

Z HTTP/1.1 Specification Section 14.10:

HTTP/1.1 definiuje „zamknij” możliwość podłączenia się do nadawcy sygnał, że połączenie zostaje zamknięty po zakończeniu reakcji .

Tak więc, jeśli mamy przejść HTTP Content-Length nagłówek oprócz Connection: close przeglądarka wie, aby zamknąć połączenie po odebraniu określonej długości odpowiedź:

  1. Buforuj WSZYSTKIE wyjścia skryptu, aby zachować możliwość wysyłania nagłówków.
  2. Po uzyskaniu pełnych danych wyjściowych wyślij odpowiednie nagłówki do klienta.
  3. Kontynuuj r przetwarzanie ... ale nie próbuj wysyłać danych wyjściowych lub otrzymasz błędy, ponieważ nagłówki zostały wysłane.

Należy również zachować ostrożność, ponieważ można uzyskać więcej czasu na wykonanie skryptu w SAPI serwera WWW, jeśli przetwarzanie jest zbyt duże. Na koniec powinieneś powiedzieć PHP, aby zignorował "user abort" w tym konkretnym skrypcie, używając ignore_user_abort(), ponieważ przeglądarka zamknie połączenie w wyniku tego, co robisz i chcesz, aby PHP kontynuowało przetwarzanie.

<?php 
ignore_user_abort(); 
ob_start(); 

// do stuff, generate output 

// get size of the content 
$length = ob_get_length(); 

// tell client to close the connection after $length bytes received 
header('Connection: close'); 
header("Content-Length: $length"); 

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

// close session if you have one ... 
// continue your processing tasks ... 
?> 

Można zbadać sekcji podręcznika PHP na Connection handlingdocs.

Alternatywnie, dlaczego nie rozpocząć buforowania wyjściowego? Następnie możesz przechwycić wszystkie dane wyjściowe, które zostaną wysłane, a następnie zdecydować później, jeśli chcesz coś z tym zrobić.

<?php 

echo 'before output buffering'; 
ob_start(); 
echo 'after output buffering'; 
$output = ob_get_contents(); 

// script's only output to this point will be 'before output buffering' 

// I changed my mind, send the output ... 
ob_end_flush(); 
?> 
+0

Buforowanie wyjściowe nadal utrzymuje otwarty strumień wyjściowy w przeglądarce. Załóżmy, że muszę wykonać pewne przetwarzanie, które potrwa kilka sekund, a przeglądarka zaczeka, aż przetwarzanie zostanie zakończone. Zwłaszcza w przypadku AJAX spowolni to znacznie webaplikację. Dlatego chcę mieć możliwość zamknięcia połączenia z przeglądarką, aby przeglądarka mogła przetworzyć dane wyjściowe, a następnie kontynuować przetwarzanie końcowe. – Tiddo

+0

@Tiddo Zaktualizowałem swoją odpowiedź (uważam, że jest) odpowiednim rozwiązaniem. – rdlowrey

+0

To całkiem niezłe rozwiązanie! Spróbuję tego za chwilę. Edycja: działa świetnie! Wielkie dzięki! – Tiddo

0

nie mam wystarczającej reputacji wypowiedzenia się, ale chcę podzielić się, że odpowiedź @rdlowrey gzip może być problem.

Jeśli masz gzip umożliwiło Transfer-Encoding nagłówek jest zawsze ustawiony na pakietowego, nawet jeśli starają się zmienić go header("Transfer-encoding: none"); dlatego nie wyśle ​​Content-Length nagłówek.

Sposób mogę rozwiązać ten problem był przy następnym wcześniej:

<? 
@ini_set('zlib.output_compression', 'Off'); 
@ini_set('output_buffering', 'Off'); 
@ini_set('output_handler', ''); 
@apache_setenv('no-gzip', 1); 
?> 

a następnie roztwór:

<? 
ignore_user_abort(); 
ob_start(); 

// do stuff, generate output 

// get size of the content 
$length = ob_get_length(); 

// tell client to close the connection after $length bytes received 
header('Connection: close'); 
header("Content-Length: $length"); 

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

// close session if you have one ... 
// continue your processing tasks ... 
?>