php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #23843 No way to push multiple pages/generate "please wait" message
Submitted: 2003-05-27 16:38 UTC Modified: 2003-05-30 19:43 UTC
From: kop at meme dot com Assigned:
Status: Not a bug Package: Feature/Change Request
PHP Version: 4.3.1 OS: Linux 2.4.18-27.7.xsmp (RH)
Private report: No CVE-ID: None
 [2003-05-27 16:38 UTC] kop at meme dot com
I lied.  I developed on php 4.1.2 (Apache 1.3.27) but I see from the
documentation there's no fix in future releases.

This request could also be catagorized under:
Network -> HTTP Related

There's no way to use php to send multiple web pages (mime multipart/mixed
messages) in response to a single http 1.1 request, as is needed to do
things like generate a "Please wait" page while a long database query
is running.  Bugzilla is an example of an application which uses this
technique to generate a "Please wait" message.

Note that this is a w3 approved usage of multipart/mixed.  See:
http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html

The immediate problem is that the header() function does nothing (but
issue warnings) once output is generated by a php script.  This 'extra
safety feature' breaks a useful functionality.  To retain a completely
general ability to mess with http headers, header() should be able to
output at any time, and the output of header() should be dependent
upon execution order.  (Clearly, there are issues surrounding the
empty lines that delimit http headers from content.  Perhaps these
could be auto-generated as php knows whether content has been output.)

Alternately, there could be a way to prevent php from generating any
headers, leaving all http header generation up to the php script.  But
it's nice to have php "do headers" so the programmer doesn't have to
know everything about everything.

An appealing solution is to have a "begin_mime_part([content_type]);"
function.  Content type would default to "text/html".  This function
must be used before any output is generated, as with header().
header() may be called anytime after a call to begin_mime_part(), the
resultant headers would apply to the part.  The first time
begin_mime_part() is called it would generate the content boundary
string (a good one, not like in my example below) and output a
Content-type: of mime/multipart, as well as a content boundary and a
Content-type: header for the mime part.  Begin_mime_part() _may_ also
be called at any time during script execution, at which point it will
output the content boundary, flush(), and another Content-Type: header..  Scripts that call begin_mime_part() must
(transparently to the php coder) output the content boundary when the
script exits.

Here's my sample php script to generate a "please wait" page, that
doesn't work.  (Untested, of necessity.)


<?php
/* Example of how to do a "please wait" message while a web page loads.
 *
 * May 27, 2003
 *
 * Karl O. Pinc <kop@meme.com>
 *
 * The idea is to send two complete web pages in response to a single
 * client request.  The first page has the "please wait" message, the
 * second is the data we want to deliver.  We send two pages by returning
 * multipart mime document, each page being a separate part.
 *
 * For this page to work with apache/php the php short_open_tag configuration
 * directive must be set to "off", so the xml declaration is passed to the
 * client.  Put "php_flag short_open_tag off" (in a <Directory> directive?)
 * in /etc/httpd/conf/httpd.conf or a .htaccess file.
 *
 * Note that this page relies on the w3.org site for the
 * xhtml dtd declaration.  If you want to be stand-alone, copy
 * the document to your own server and adjust the URLs in the doctype
 * declaration.  (The xmlns namespace in the "head" tag is a string
 * identifying the namespace, not a document.)
 *
 * Technique from "The Linux Journal, Issue 82", "Web Servers and
 * Dynamic Content", http://www.linuxjournal.com/article.php?sid=4386, the
 * section titled "Pushing Continual Updates to the Browser".
 */

// (Recall, header() _must_ be called before any output is sent.  Check
//  those require()-s!  You may want to convert them to include()-s.)

// Have the server tell the client we'll be sending a multipart mime document.
header('Content-;Type:multipart/x-;mixed-;replace;boundary=SoMeRaNdOmTeXt');
header('--SoMeRaNdOmTeXt');
header('Content-type: text/html');

?>
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="markup.css"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Test page -- waiting</title>
</head>
<body>
<p>
Please wait while our computer does something important sounding....
</p>
</body>
</html>

<?php
// Finish up the first page, and send it.
header('--SoMeRaNdOmTeXt', TRUE);
flush();


// Wait 5 seconds, so we can read the first page.
sleep(5);

// Start the second page.
header('Content-type: text/html', TRUE);
?>
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="markup.css"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Test page</title>
</head>
<body>
<p>
All done.  Ain't you glad you waited?
</p>
</body>
</html>
<?php

// Finish up the second page and send it.
header('--SoMeRaNdOmTeXt', TRUE);
?>


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-05-27 16:44 UTC] kop at meme dot com
Whoever develops the solution to this problem may also want to think in terms of "multipart/alternative", which are alternative representations of the same data, as well as "multipart/mixed", which should be presented to the user in series.
 [2003-05-27 18:16 UTC] michael dot mauch at gmx dot de
Thank you for pointing out that interesting technique (at least I was not aware of it).

There's not much magic in the header function - it's just like "print", but it allows to overwrite the HTTP headers that are sent to the browser _before_ your HTML page. "Headers" in the middle of the HTML page are no headers in this sence, they are just normal text.

After replacing the "-;" in the Linux Journal article with "-", the C code can be translated directly into PHP:

<?php

$Boundary = "SoMeRaNdOmTeXt";
header("Content-Type: multipart/x-mixed-replace; boundary=$Boundary");

print "-$Boundary\n";
for($i=1; $i<=10; $i++)
{
  print "Content-type: text/html\n\n";
  print "<HTML><HEAD></HEAD><BODY><H3>Update #$i</H3></BODY></HTML>\n";
  print "\n-$Boundary\n";
  flush();
  sleep(1);
}

print "Content-type: text/html\n\n<HTML><HEAD></HEAD>"
."<BODY><H3>That's all kids!</H3></BODY></HTML>\n";
flush();

?>
 [2003-05-27 19:32 UTC] sniper@php.net
Heh..tested that script by Michael, it does work fine..ON Mozilla based browsers. :)

IE6 didn't like it.

Anyway, as this is already possible -> bogus.

 [2003-05-27 21:26 UTC] kop at meme dot com
You are right.  This can be done with straight php.  It 
doesn't matter where in the headers the "Content-Type: 
multipart/mixed" is so it doesn't matter that the header()
ordering is indeterminate.

All the same, it'd still be handy to have a 
begin_mime_part() function, as the syntax of RFC1341 is 
kinda persnickity.  (See url referenced above.) 
Probably the reason why michael's code 
didn't work in IE 6 is that his message does not end with a 
boundry.  And the boundry does not appear with two dashes in
front of it when used, and there are some issues regarding
CR/LF requirements around the boundry which arn't met.
  
The fussyness of where CRLF's are required and where, when
optionally present, they change the content type to 
text/plain is worth a function.  And if you _do_ have a
begin_mime_part() function it'd be much nicer to have it built-in php because then you wouldn't have to have a 
(required) corresponding end_mime_part() function to call 
to put in the last boundry string, php could do it 
automatically.

Any way to move this request from a "bug-- can't do this" 
status to a "enhancement request -- be nice to make this 
easier" status?
 [2003-05-30 19:43 UTC] kop at meme dot com
This technique just flat out doesn't work with MS Internet Explorer.  As they have 94% of the market, there's no point in pursuing this.

FYI, I published some clean example code to the php-general mailing list.  Subject: "Please wait"/server push sample code
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon May 20 05:01:32 2024 UTC