How to make PHP ob_flush send headers before page complete?

Problems with the Windows version of XAMPP, questions, comments, and anything related.

How to make PHP ob_flush send headers before page complete?

Postby markosjal » 06. September 2021 05:05

I am using XAMPP 8.08 on Windows. Trying to get headers to flush out before page is done executing
Php info say buffering is disabled but there may be an Apache Buffer as well??

Here is my php code.

Code: Select all
<?php
ob_start();
header("Cache-Control: no-cache, no-store, must-
revalidate"); // HTTP 1.1.
header("Pragma: no-cache"); // HTTP 1.0.
header("Expires: 0"); // Proxies.
header('HTTP/1.1 201 Created');
header('Location:
http://'.$ipaddress.':'.$port.'/path/file');
ob_flush();
flush();

...Here there is a Bunch of code that takes a very long time to execute....

?>
markosjal
 
Posts: 14
Joined: 27. May 2011 08:41

Re: How to make PHP ob_flush send headers before page compl

Postby Nobbie » 06. September 2021 11:19

You probably want to achieve the execution of a script AFTER the browser has closed the connection. And that is already the problem, i think the buffer is flushed, but the browser does not continue until the TCP connection is closed. In one word: thats not the way it works.

Instead use the register_shutdown_function() of PHP, which executes a script AFTER the connection has been closed (i.e. after an exit() has been executed in the main PHP script).

See https://www.php.net/manual/en/function. ... nction.php

P.S.: Due to the documentation, it seems that the connection will remain open even until the shutdown function has ended. That would mean, that it still does not work, because the browser does not issue a new request before the current request is closed. Therefore you should try to separate the PHP code into a another file and execute it in the background (there are tons of tutorials how to do that, for example https://florian.ec/blog/php-background-processes/). Anyway, you should give it a try using shutdown function.

For running a task in the background without WAITING for it, i found this usefull snippet in https://stackoverflow.com/questions/381 ... for-result

I know this question has been answered but the answers i found here didn't work for my scenario ( or for Windows ).

I am using windows 10 laptop with PHP 7.2 in Xampp v3.2.4.

Code: Select all
$command = 'php Cron.php send_email "'. $id .'"';
if ( substr(php_uname(), 0, 7) == "Windows" )
{
    //windows
    pclose(popen("start /B " . $command . " 1> temp/update_log 2>&1 &", "r"));
}
else
{
    //linux
    shell_exec( $command . " > /dev/null 2>&1 &" );
}


This worked perfectly for me.

I hope it will help someone with windows. Cheers.


Instead of "temp/update_log" you also simply use the special device NULL (or - due to Wikipedia - also \Device\NULL) under Windows (which corresponds to /dev/null under Linux) and for $command you may also use the c:/xampp/bin/php.exe Interpreter with a filename.

P.P.S.: Found this interesting example in the User notes of register_shutdown_function():

I had a lot of problems getting a redirect to work, after which my script was intended to keep working in the background. The redirect to another page of my site simply would only work once the original page had finished processing.

I finally found out what was wrong:
The session only gets closed by PHP at the very end of the script, and since access to the session data is locked to prevent more than one page writing to it simultaneously, the new page cannot load until the original processing has finished.

Solution:
Close the session manually when redirecting using session_write_close():

Code: Select all
<?php
ignore_user_abort(true);
set_time_limit(0);

$strURL = "PUT YOUR REDIRCT HERE";
header("Location: $strURL", true);
header("Connection: close", true);
header("Content-Encoding: none\r\n");
header("Content-Length: 0", true);

flush();
ob_flush();

session_write_close();

// Continue processing...

sleep(100);
exit;
?>


But careful:
Make sure that your script doesn't write to the session after session_write_close(), i.e. in your background processing code. That won't work. Also avoid reading, remember, the next script may already have modified the data.

So try to read out the data you need prior to redirecting.


As said, the connection must be closed for the browser, thats what the above script example is doing. Seems to be exactly what you are looking for.
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04

Re: How to make PHP ob_flush send headers before page compl

Postby markosjal » 07. September 2021 14:25

I thank you for your reply but I do not believe it to be entirely accurate

You seem to imply it is not possible to flush out the part of the page already executed to the browser and continue processing PHP on the page however I know this to be possible.

in fact I resolved my own issue this way:

Code: Select all
<?php
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
header('HTTP/1.1 201 Created');
header('Location: http://'.$ipaddress.':'.$port.'/$path/$file');
$size = ob_get_length();
header("Content-Length: $size");
header('Connection: keep-alive');
header('Keep-Alive: timeout=500, max=1000');
ob_start();
ob_end_flush();
flush();

...then a whole bunch of code processes here that I know is working, and can take a few minutes to complete....




The headers are sent in an immediate reply, the connection remains open, and the code on the page is processing.

The challenge I have now is getting Keep-alive working
markosjal
 
Posts: 14
Joined: 27. May 2011 08:41

Re: How to make PHP ob_flush send headers before page compl

Postby Nobbie » 07. September 2021 14:38

markosjal wrote:You seem to imply it is not possible to flush out the part of the page already executed to the browser and continue processing PHP on the page


No, thats not what i said. The problem is the connection, as long it remains open, the browser does not issue another request. And vice verse, if the browser issues a new request, the connection to the previous site will be closed. That is the problem. The browser cannot handle two requests in a single open tab. But you want to have him going to another location (due to the Location Header), therefore the browser must send a new request to the location you applied in the location header, but still should wait for the old request. That does not work.

Of course you may succeed in running a script while the browser already requests a new page, but this still means, that the old connection is closed.
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04

Re: How to make PHP ob_flush send headers before page compl

Postby markosjal » 08. September 2021 20:29

ok
let me explain about this situation as I understand It I am going to post some real world examples.

I am dealing with eSCL protocol which you can find more info on here https://mopria.org/spec-download

I can see the following in phpinfo:
Code: Select all
Max Requests   Per Child: 0 - Keep Alive: on - Max Per Connection: 100
Timeouts   Connection: 300 - Keep-Alive: 5
....
output_buffering   4096

Now I have not been able to change the Keep-alive connection or time-put settings no matter what I do.

The output buffering "off" or "4096" seems to make no difference at least with my code, and without the ability to change the keep-alive settings.

on the original ob_flush question , I ended up with this
Code: Select all
<?php
header("Cache-Control: no-cache, no-store, must-revalidate");
header('HTTP/1.1 201 Created');
header('Location: http://'.$ipaddress.':'.$port.'/eSCL/ScanJobs');
$size = ob_get_length();
header_remove('X-Powered-By');    //removes the 'X-Powered-By' header
header('Content-Type:');               //removes the 'Content-Type' header
header("Content-Length: $size");
header('Connection: keep-alive'); //Connection: keep-alive
//header('Keep-Alive: timeout='.$keepalivetimeout.', max='.$keepalivemax);// this seemed to do nothing
ob_start();
ob_end_flush();
flush(); 

It took some time to come up with the above solution however I can confirm with CURL that it is working as expected.

I have an HP scanner that uses this protocol and can use it as a model to try to replicate. I can send a CURL request and get the response below:
Code: Select all
curl -v -X POST -d @1inchoffset.xml  http://192.168.0.250:80/eSCL/ScanJobs
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 192.168.0.250...
* TCP_NODELAY set
* Connected to 192.168.0.250 (192.168.0.250) port 80 (#0)
> POST /eSCL/ScanJobs HTTP/1.1
> Host: 192.168.0.250
> User-Agent: curl/7.55.1
> Accept: */*
> Content-Length: 749
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 749 out of 749 bytes
< HTTP/1.1 201 Created
< Cache-Control: no-cache, no-store, must-revalidate
< Location: http://:80/eSCL/ScanJobs/0pvnag6j-8jcq-1adm-1001-c6lj2g43
< Server: gSOAP/2.7
< Content-Length: 0
< Connection: keep-alive
<
* Connection #0 to host 192.168.0.250 left intact


Now I have a Windows machine that I am trying to make emulate that behavior to share the Twain or WIA scanner. and I am 99% of a final working product, except for a connection issue that I think relates to keep-alives

When I send this or a similar command to the Windows server
Code: Select all
curl -v -X POST -d @Platen75PNG2_5Doc.xml  http://192.168.0.40:8000/eSCL/ScanJobs
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 192.168.0.40...
* TCP_NODELAY set
* Connected to 192.168.0.40 (192.168.0.40) port 8000 (#0)
> POST /eSCL/ScanJobs HTTP/1.1
> Host: 192.168.0.40:8000
> User-Agent: curl/7.55.1
> Accept: */*
> Content-Length: 811
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 811 out of 811 bytes
< HTTP/1.1 201 Created
< Date: Wed, 08 Sep 2021 18:51:06 GMT
< Server: Apache/2.4.48 (Win64) OpenSSL/1.1.1k PHP/8.0.8
< Cache-Control: no-cache, no-store, must-revalidate
< Location: http://192.168.0.40:8000/eSCL/ScanJobs
< Content-Length: 0
< Connection: keep-alive
<
* Connection #0 to host 192.168.0.40 left intact


So it looks like so far I have the POST command replicated.

After sending that above POST command from a client such as Imaging on OSX, I can see that both the Windows server and the scanner later start to receive requests from the client to /eSCL/ScannerStatus , which is where the document count is located as well as repeating the same URL in the location header reply once the document is ready for download.

I can replicate this manually with curl to initiate the post and a browser to see /eSCL/ScannerStatus and also see what that Mac app sees and have seen it in wireshark traces.

The problem is that after about 50 to 60 seconds after initiating the scan on the Mac App (OSX 10.14 Mojave running on Virtualbox), it seems to fail when the spinning disc disappears, but the "scanning Document..." message remains. The scanned document(s) never appear in Imaging, unless it is single sheet which takes about 40 seconds to scan on the slow Dell 1355cn Scanner at 300 dpi )(with the scanner already "warmed up". I have seen similar results in Linux using the https://github.com/alexpevzner/sane-airscan package but have not tested the latest version of my code with a Linux client lately.

Here is another factor to complicate matters: I have also tested with the 'Official" Mopria Scan for Android app. The Mopria Scan for Android app works 100% , even with a very slow sheetfeed scanner scanning multiple pages , it seems to patiently wait till the scan is done then downloads all the files.

So how do I adjust the Keep-alive timeout and keep-alive and connection time-outs? Unsure as to how these time - outs seem to relate to about 50 to 60 seconds and whether or not they are the cause, but i see many sites that say they should be increased for many different reasons. It seems waiting for a slow document scanner might be a good reason.

of course if anyone has a Windows 10 machine, windows scanner and a Mac and wants to help that is extremely helpful too.
Last edited by markosjal on 08. September 2021 21:23, edited 1 time in total.
markosjal
 
Posts: 14
Joined: 27. May 2011 08:41

Re: How to make PHP ob_flush send headers before page compl

Postby Nobbie » 08. September 2021 21:22

Actually - all this does has nothing to do with "Xampp for Windows" (what this forum is made for) and i wish you good luck in running your scanner. But its not supported by this forum and I even cannot run any test. I have no clue about the idea of scanning a remote document, which somehow must be put on the scanner. Why not simply scanning it at the PC? And also every Smartphone has a nice camera to scan documents. I dont get it.

Thats weird for me, good luck.
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04

Re: How to make PHP ob_flush send headers before page compl

Postby markosjal » 09. September 2021 07:40

Nobbie wrote:Actually - all this does has nothing to do with "Xampp for Windows" (what this forum is made for) and i wish you good luck in running your scanner. But its not supported by this forum and I even cannot run any test. I have no clue about the idea of scanning a remote document, which somehow must be put on the scanner. Why not simply scanning it at the PC? And also every Smartphone has a nice camera to scan documents. I dont get it.

Thats weird for me, good luck.


Yes some people need things "dumbed down" like scanning 20 page documents with a camera instead of a scanner is a LOT of work! Then again there are those that already know it all. including that HP and Apple's eSCL protocol is frivolous in the day of cameras on phones.

On "dumbing it down" even further......

Actually explaining that the "Flush" was achieved on the Windows host running XAMPP and ran into a new problem unable to set Keep-alive timeout and connection time-outs on that same XAMPP for WIndows server, in fact has EVERYTHING to do with XAMPP for Windows. This applies whether you see that or not. The problem here is that when I post too few details I am often scolded for that . Now I post too many details so that someone like you comes along saying it is NOT RELEVANT?

There was actually a new thread made for this new issue of keep alives and connection time outs here
viewtopic.php?f=16&t=81278
markosjal
 
Posts: 14
Joined: 27. May 2011 08:41

Re: How to make PHP ob_flush send headers before page compl

Postby Nobbie » 09. September 2021 10:57

No, you are totally wrong.

Xampp is NOT a software tool, its a distribution. A collection of third party software, with the goal of providing an easy installation. If you think, that (for example) Apache behaves differently than in other environments (linux for example), you should ask Apache Development. Bitnami does not make any Development, they are only building the package. This forum is meant for installation issues of Xampp, not for Development Issues of Apache.

Finally, this forum does not support any other 3rd party tools like WordPress or so and same for any issues with your scanner software. This is simply the wrong forum.
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04

Re: How to make PHP ob_flush send headers before page compl

Postby markosjal » 09. September 2021 22:05

Nobbie,

1) I see no official standing that you have in these forums to say what it is for or what it is not, nor for you to "judge" a post.

2) Configuring a server is a big part of installing it including this current question on setting timeouts . I can not believe that any "official" moderator here would disagree with the fact that configuring Apache is relevant.

3) I will ask you publicly as I did in private to refrain from future replies on my posts . Having you trying to negate the validity of my post in no way helps me to find an answer. Please abstain also from all messages directly to me.

4) That you do not like or approve of my use of XAMPPP is irrelevant . It is a web server suite to be used as needed. I do not ask for, nor seek your nor anyone's endorsement or recognition in any way. MANY MANY apps use integrated web servers and if this gets me from a to b, at least for now that is all that matters.

Hasta nunca

Mark
markosjal
 
Posts: 14
Joined: 27. May 2011 08:41

Re: How to make PHP ob_flush send headers before page compl

Postby Altrea » 09. September 2021 23:41

Hi,

markosjal wrote:1) I see no official standing that you have in these forums to say what it is for or what it is not, nor for you to "judge" a post.

Is it important for you whether someone is a Moderator/Administrator to tell his/her opinion about the scope of support of this board? At the end it is only one opinion.
You can have a different opinion and i can have a different opinion. At the end this doesn't matter at all.
I have written forum rules years ago which should give you some orientation about Scope of support. Besides this every forum has a Description that could help. But that are only hints, not hard rules.

markosjal wrote:2) Configuring a server is a big part of installing it including this current question on setting timeouts . I can not believe that any "official" moderator here would disagree with the fact that configuring Apache is relevant.

The borders are fluent. Configuring a server can be anything between "getting the new Facebook 2.0 running" and "having troubles with execution timeout of 3 line of code".
We cannot provide the full bandwith of all these topics. At the end every respondent must choose for hisself/herself, if the time and knowledge needed to invest to provide proper help is in his personal scope or not.

markosjal wrote:3) I will ask you publicly as I did in private to refrain from future replies on my posts . Having you trying to negate the validity of my post in no way helps me to find an answer. Please abstain also from all messages directly to me.

Every board member is free to reply to any topic. If the answer is not relevant for you or don't fit your expectations, feel free to simply don't read or response to it. This will in no way prevent other helpers replying to your topic. The number of active helpers here is very limited also, so...
We don't provide any support via personal channels like PM, email, Skype, TeamViewer!

It's like porn for programmers 8)
User avatar
Altrea
AF Moderator
 
Posts: 11936
Joined: 17. August 2009 13:05
XAMPP version: several
Operating System: Windows 11 Pro x64

Re: How to make PHP ob_flush send headers before page compl

Postby markosjal » 15. September 2021 01:43

If everyone is allowed to be criticized for asking RELEVANT questions these forums become useless especially when it is a "self professed expert" who really has no idea whatsoever. getting something to work making adjustments is a =normal part of any software package like Apache I am really sorry that you as a moderator even agree to acknowledge that and yourself try to imply otherwise. Sad state of your forums

OS as stated in yuor rules and reaffirmed BY YOU , I can ask anyone I want to stop replying to my threads.
markosjal
 
Posts: 14
Joined: 27. May 2011 08:41


Return to XAMPP for Windows

Who is online

Users browsing this forum: No registered users and 222 guests