That's a client-side issue then, because it is certainly sent. Trying your exact script: <?php ignore_user_abort(true); header("Location: redirect2.html"); echo "foo\n"; flush(); for($i=0;$i<10;$i++) { echo $i; sleep(1); } $fp = fopen("/tmp/foo.txt","a"); fputs($fp,$i); fclose($fp); ?> It's at http://lerdorf.com/red.php if you want to test it yourself. 3:53pm colo:/var/www/lerdorf.com> telnet localhost 80 Trying 127.0.0.1... Connected to colo. Escape character is '^]'. GET /red.php HTTP/1.0 HTTP/1.1 302 Found Date: Tue, 26 Jul 2005 22:53:40 GMT Server: Apache/1.3.33 (Debian GNU/Linux) PHP/4.4.1-dev X-Powered-By: PHP/4.4.1-dev Location: redirect2.html Connection: close Content-Type: text/html; charset=utf-8 foo <10 second delay here> Connection closed by foreign host. -Rasmus Liang ZHONG wrote: > Thank you for replying. Sorry for being long again. > I tried your suggestion of this: > > <?php > ignore_user_abort(true); > header("Location: redirect2.html"); > echo "foo\n"; flush(); > for($i=0;$i<10;$i++) { echo $i; sleep(1); } > $fp = fopen("/tmp/foo.txt","a"); > fputs($fp,$i); > fclose($fp); > ?> > > The browser did not get the redirect page until the new $i(10) has been > appended to file foo.txt. > > I also tried > ----------------------------------------------- > ob_start(); > header("Location: http://liang.ns2user.info/php/y.html"); > echo "foo\n"; > ob_end_flush(); > ----------------------------------------------- > > And does not work. > > I think it might be the case of what you suggest: > >> If the >> client sticks around after seeing the redirect and doesn't redirect >> until after the server has closed the connection, then there is no way >> to force a close. > > > So may I draw the conclusions: > 1. Server in php can not actively close the connection to make the > client see the redirect page immediately after the header has been set? > 2. The connection is not closed even when the main php end and the > shutdown function is running? > > If above conclusions are not true, could be somewhere that might be > wrong due to the apache-php configuration or what? > > If those are true, I think I have to re-design the project flow control > and it will take sometime while I have already finished the code > assuming no above problem. Also I think this might result an awkward > design for the project. (I mean jsp will be easier to achieve a > relatively more elegant design). > > I use several other program langurages for many years, but new to php, > so I probably made some assumption base on my experiences of other > langurages but not true. The project I am working now to add > enhancements is written on php. I try to keep the main design of it. I > did not expect it would be difficult to achieve this: > > 1. write an xml page > 2. let http client get this xml page in time > 3. continue do something time consuming > > now I have difficulty in 2 and 3. My client is normally perl > LWP::UserAgent, and sometimes browser. I wonder how to let the client > get the page in time before I can continue to finish the rest of the > work. Otherwise the client will timeout and get no result. > > Please help! Thank you. > > Liang > >> >> I really didn't follow all that. But this stuff is not that complex. >> header() sets a header to be sent when output goes out. header() does >> not send an actual header at that point. If you don't send any output, >> then the headers won't go out until the script terminates. If you have >> any sort of output buffering enabled, then even if you think you are >> sending something, you may only be buffering it, and in that case again >> the headers won't go out until the request is done. >> >> Also, ignore_user_abort() controls whether or not your script will be >> terminated when we are able to detect that the user has aborted. A user >> abort is defined as nobody being around to read the data we are sending >> out. If you don't send anything, we can't detect if the browser has >> gone away. Generally browsers will redirect as soon as they see a >> Location: redirect header, but that could be client-speficic. If the >> client sticks around after seeing the redirect and doesn't redirect >> until after the server has closed the connection, then there is no way >> to force a close. If it does redirect and close its end of the >> connection, then if you set ignore_user_abort(false) your script will be >> terminated as soon as it tries to send something further and your >> shutdown function will be called at that point. >> >> -Rasmus >> >> Liang ZHONG wrote: >> > Hi Rasmus, >> > >> > This may be a little bit long, sorry for taking your time. >> > >> > It still does not work as expected. I tried some experiment, and found >> > that if I called some function or write some code line other then >> > calling header(), the register_shutdown_function and other part of >> codes >> > work as expected . For example: >> > <?php >> > set_time_limit(5); >> > function f(){ >> > set_time_limit(10); >> > //doing something time consuming >> > } >> > >> > some_function(); >> > >> > ?> >> > The time limit of 5 will be the limit of the some_function() and the 10 >> > will be the limit of function f() respectively. >> > >> > Code example: >> > >> > >> ----------------------------------------------------------------------------------------------------------------------- >> >> > >> > <?php >> > set_time_limit(1); >> > ignore_user_abort(true); >> > >> > function say_goodbye() { >> > $st = connection_status(); >> > print "Status 1: ".$st."\n"; >> > set_time_limit(10); >> > $st = connection_status(); >> > print "Status 2: ".$st."\n"; >> > >> > $count=20000000; >> > for($i=0; $i<$count; $i++){ } >> > print "End!\n"; >> > exec("touch /home/.nappy/liang/liang.ns2user.info/php/bbb"); >> > } >> > >> > register_shutdown_function("say_goodbye"); >> > print "Sleeping...\n"; >> > >> > $count=10000000; >> > for($i=0; $i<$count; $i++){ } >> > >> > print "Done!\n"; >> > >> > ?> >> > >> ------------------------------------------------------------------------------------------------------------------------ >> >> > >> > -bash-2.05b$ curl -N liang.ns2user.info/php/v.php >> > Sleeping... >> > <br /> >> > <b>Fatal error</b>: Maximum execution time of 1 second exceeded in >> > <b>/home/.nappy/liang/liang.ns2user.info/php/v.php</b> on line >> > <b>30</b><br /> >> > Status 1: 2 >> > Status 2: 2 >> > End! >> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> > if I change the time limit from 10 to 5 in function f() >> > >> > -bash-2.05b$ curl -N liang.ns2user.info/php/v.php >> > Sleeping... >> > <br /> >> > <b>Fatal error</b>: Maximum execution time of 1 second exceeded in >> > <b>/home/.nappy/liang/liang.ns2user.info/php/v.php</b> on line >> > <b>30</b><br /> >> > Status 1: 2 >> > Status 2: 2 >> > <br /> >> > <b>Fatal error</b>: Maximum execution time of 5 seconds exceeded in >> > <b>/home/.nappy/liang/liang.ns2user.info/php/v.php</b> on line >> > <b>14</b><br /> >> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> > Change both the time limit to 10 will result: >> > >> > -bash-2.05b$ curl -N liang.ns2user.info/php/v.php >> > Sleeping... >> > Done! >> > >> > Status 1: 0 >> > Status 2: 0 >> > End! >> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> > >> > But if the some_function is header() then the rule above does not work. >> > It seems the function f()'s time limit also rule the header(). Only >> > after the registered shutdown function finishes runing normally or by >> > hit the expire time limit, will the header() return page to >> browser/http >> > user agent. Example code with suggestion from Rasmus as: >> > >> > >> ------------------------------------------------------------------------------------------------------------------ >> >> > >> > <?php >> > >> > set_time_limit(5); >> > >> > function f(){ >> > set_time_limit(100); >> > $count=500000000; >> > for($i=0; $i<$count; $i++){ >> > //sit here and loop for a bit so we can have time to hit Stop... >> > echo "a \n"; flush(); >> > } >> > echo "end"; >> > exec("touch /tmp/aaa"); >> > } >> > >> > register_shutdown_function('f'); >> > >> > ignore_user_abort(true); >> > header("Content-type: text/plain"); >> > header("Location: y.html"); >> > >> > echo "foo\n"; flush(); >> > for($i=0;$i<10;$i++) { echo $i; sleep(1); } >> > $fp = fopen("/tmp/foo.txt","a"); >> > fputs($fp,$i); >> > fclose($fp); >> > ?> >> > >> > >> ------------------------------------------------------------------------------------------------------------------ >> >> > >> > After the file /tmp/foo.txt has been created, before the file /tmp/aaa >> > being created, the y.html will not get to the browser or perl program >> > using LWP::UserAgent. I think it is no way to close the connection >> > actively by the php program to deliver the page sooner to end the http >> > request, even I add lines and make code like this does not work: >> > >> > ---------------------------------------------------------------- >> > header("Content-type: text/plain"); >> > header("Cache-Control: no-store, no-cache"); >> > header("Location: y.html"); >> > header("Connection: close"); >> > ---------------------------------------------------------------- >> > >> > My project act as a broker for user agent to a library database server >> > called z39.50. Upon the request from user agent, my program need to >> > connect a z39.50 server, getting data back 1 by 1, transforming to >> > sepcial xml format and sending back to the request party. When the data >> > repository is huge (sometimes up to million records), I have to get >> > partial data transform and send back to user agent (normally a piece of >> > perl code, called harvester) with a resumption token. The harvester >> will >> > in a while loop send out another http request with the last resumption >> > token and fetch data of next part, until finish all data fetching. The >> > time to connect the database and do the query is a constant >> overhead. So >> > it is not a good design that program need to connect the database and >> > query upon each request with or with out resumption token. So my design >> > is to connect to database and query only when the first initial request >> > comes, and reponse back with partical data using header() and continue >> > getting back data from z39 server. Upon next request, the program will >> > only need to make sure the data needed has already stored in the >> > harddrive and transform them and send them back. >> > Since the user harvester agent normally has a 180 second timeout, it is >> > necessary to respond within that period of time. >> > >> > I really need your suggestion. Thank you very much again. >> > >> > >> > Liang >> > >> > >> > >> > >> >> Try somthing lik >> > >> > >> > e this: >> > >> >> >> >> <?php >> >> ignore_user_abort(true); >> >> header("Location: redirect2.html"); >> >> echo "foo\n"; flush(); >> >> for($i=0;$i<10;$i++) { echo $i; sleep(1); } >> >> $fp = fopen("/tmp/foo.txt","a"); >> >> fputs($fp,$i); >> >> fclose($fp); >> >> ?> >> >> >> >> >> >> Liang ZHONG wrote: >> >> > Sorry, does not seem to work here. The code below takes minutes >> to show >> >> > up in browser. >> >> > >> >> > Any more suggestion? >> >> > >> >> >> --------------------------------------------------------------------------------------- >> >> >> >> >> > >> >> > <?php >> >> > >> >> > set_time_limit(5); >> >> > >> >> > function f(){ >> >> > set_time_limit(100); >> >> > $count=500000000; >> >> > for($i=0; $i<$count; $i++){ } >> >> > echo "end"; >> >> > exec("touch /home/.nappy/liang/liang.ns2user.info/php/aaa"); >> >> > } >> >> > >> >> > register_shutdown_function('f'); >> >> > >> >> > ignore_user_abort(true); >> >> > header("Content-type: text/plain"); >> >> > header("Location: y.html"); >> >> > >> >> > $count=50000; >> >> > for($i=0; $i<$count; $i++){ echo " \n"; } >> >> > flush(); >> >> > ?> >> >> > >> >> >> --------------------------------------------------------------------------------------- >> >> >> >> >> > >> >> > >> >> > Liang >> >> > >> >> >> >> >> >> If you don't flush some output after setting the header() then the >> >> >> headers won't go out until the end of the request. So do something >> >> like: >> >> >> >> >> >> ignore_user_abort(true); >> >> >> header("Location: http://whatever"); >> >> >> echo "foo\n"; flush(); >> >> >> >> >> >> Then whatever comes after this should run and the browser is long >> >> gone. >> >> >> >> >> >> -Rasmus >> >> >> >> >> >> >> >> >> Liang ZHONG wrote: >> >> >> > I think I did not express myself clearly. >> >> >> > >> >> >> > What I want is to be able to redirect user an existing page (let >> >> them >> >> >> > get it immediately), and to close the connection actively, NOT >> >> >> passively >> >> >> > by user abort, at last, to run the function in background. >> >> >> > >> >> >> > But the redirecting using function header() with location has a >> >> problem >> >> >> > that header() always does return the page to user after the >> entire >> >> >> > program, including registered showdown function finish running, >> >> >> which is >> >> >> > against the will. I put a time consuming task into a function >> that >> >> >> > registered to be a shutdown function and hoping it runs after the >> >> user >> >> >> > has got the redirected page and the connection has been >> closed. But >> >> >> > experiements (using browsers, curl command line tool as well as >> >> >> > perl::LWP code) show that the user got the redirected page only >> >> after >> >> >> > the shutdown function finished, which is against the >> description of >> >> >> > register_shutdown_function at php website. >> >> >> > >> >> >> > It seems only header() function use to redirect page has this >> >> problem >> >> >> > (not executed until register_shutdown_function finished) while >> other >> >> >> > functions like print()/echo(), exec() have not. >> >> >> > >> >> >> > The code looks like: >> >> >> > >> >> >> >> >> >> --------------------------------------------------------------------------------------------- >> >> >> >> >> >> >> >> >> > >> >> >> > <?php >> >> >> > set_time_limit(1); >> >> >> > >> >> >> > function f(){ >> >> >> > set_time_limit(20); >> >> >> > $count=50000000; >> >> >> > for($i=0; $i<$count; $i++){ } >> >> >> > echo "end"; >> >> >> > exec("touch /home/.nappy/liang/liang.ns2user.info/php/aaa"); >> >> >> > } >> >> >> > >> >> >> > register_shutdown_function('f'); >> >> >> > >> >> >> > header("Content-type: text/plain"); >> >> >> > header("Location: y.html"); >> >> >> > ?> >> >> >> > >> >> >> >> >> >> --------------------------------------------------------------------------------------------- >> >> >> >> >> >> >> >> >> > >> >> >> > >> >> >> > http client who sends the request to the php program will only >> >> get the >> >> >> > page back as response after function f finsihes (file aaa >> created). >> >> >> > Changing the $count will make a lot difference. >> >> >> > >> >> >> > My BIGGEST question is: >> >> >> > How to make user get the redirect page immediately after the >> >> >> header() is >> >> >> > called, and not until function f() ends, while making sure >> that the >> >> >> > function f() will finally fully (and might slowly) execute? >> >> >> > >> >> >> > Thank you very much for kindly replying. >> >> >> > >> >> >> > With high respect, >> >> >> > >> >> >> > Liang >> >> >> > >> >> >> > >> >> >> >> >> >> >> >> Liang ZHONG wrote: >> >> >> >> > My Question is: >> >> >> >> > What is the correct way to keep the function running after I >> >> >> >> redirect an >> >> >> >> > existing page to http client (which I want the client get >> >> >> immediately) >> >> >> >> > and then immediately close the connection? >> >> >> >> >> >> >> >> ignore_user_abort(true); >> >> >> >> >> >> >> >> -Rasmus >> >> >> >> >> >> >> >> -- >> >> >> >> PHP General Mailing List (http://www.php.net/) >> >> >> >> To unsubscribe, visit: http://www.php.net/unsub.php >> >> >> >> >> >> >> > >> >> >> >> >> >> -- >> >> >> PHP General Mailing List (http://www.php.net/) >> >> >> To unsubscribe, visit: http://www.php.net/unsub.php >> >> >> >> >> > >> >> >> > >> > -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php