tags:

views:

535

answers:

3

Say, I have an application/xhtml+xml content and a gif image. How can I serve (not render) these two in a single http get request (using PHP)? It should be a multipart/related content. After reading this RFC, I tried something; but it did not work. (No, I am not trying to send emails with attachment)

Thanks in advance.

EDIT: Finally I succeeded doing that. I think, it will be useful if I write how I did that. I have added this as an answer. Please look below.

+5  A: 

I'm afraid you can't for the purposes you want.

If you want to do this to serve web pages, as far as I can tell, the browsers won't work with such MIME responses for rendering pages.

If you want an example of how this messages works, send yourself an email with an attachment and on your email client (not an webmail) go to the "View source" option on the email body.

You'll see your message, the attachment and possibly other parts on the same message using the MIME Multipart encoding.

OTOH, if you want it to send email, there are libraries, like PHPMailer, that will do all the encoding for you.
If that's what you want, check this example at their website.

Edit:

You could use PHPMailer to build the message, then you just use the result, instead of actually sending the email.

Try something like this:

** This is untested code, just for a starting point **

<?php
  require_once('../class.phpmailer.php');
  $mail = new PHPMailer(true); // the true param means it will throw exceptions on     errors, which we need to catch

  try {
    $mail->MsgHTML(file_get_contents('contents.html'));
    $mail->AddAttachment('images/phpmailer.gif');      // attachment
    $mail->AddAttachment('images/phpmailer_mini.gif'); // attachment
    $mime_message = $mail->CreateBody();
    echo $mime_message;
  } catch (phpmailerException $e) {
    echo $e->errorMessage(); //Pretty error messages from PHPMailer
  } catch (Exception $e) {
    echo $e->getMessage(); //Boring error messages from anything else!
  }
?>
Carlos Lima
But there must be a way to serve multipart/related documents, isn't it? Otherwise how this(http://www.rfc-archive.org/getrfc.php?rfc=2387) can be implemented?
mshsayem
You can "serve" it, like outputting a MIME multipart message, but as I said, I think no browsers will render it the way you'd expect.
Carlos Lima
In other words, if what you want is to serve a webpage, no, it wont work. If what you want is to output a multipart document to be used/rendered by something else (like a mail client or something else), yes, you can.
Carlos Lima
Yes, that's what I want. Can you show some code? Thanks
mshsayem
I tried echoing, but it did not work. What should be the 'Content-type' of the PHP header() call? Should it 'multipart/related' only? Should I call header() 3 times, with different content-types? Or, just one header() call and echo the rests?
mshsayem
I'll add an example, just a min
Carlos Lima
Sorry. But I don't want it. "what I want to output a multipart document to be used/rendered by something else". NOT a mail client. Can you show me? Thanks for your time.
mshsayem
What I suggested is, use the PHPMailer to construct the message, then you ECHO it out, like I did in the example. You could just as well build the message manually, but that's a lot of trouble considering you have libraries that do it already. You could also edit the PHPMailer files yourself and adapt it to your needs.
Carlos Lima
Notice in the example I wrote, I dont send the email, i get the body (MIME encoded message) using `$mime_message = $mail->CreateBody();` and then I output it like this: `echo $mime_message;`
Carlos Lima
A: 

I've been trying to achieve the same thing.

It appears that MSIE is the only browser to currently support multipart/related natively (Opera may have some support - but I;ve not played around with it) however when loading such files, it seems to totally ignore the HTTP headers regarding mime type and other stuff (such as caching information, disposition etc). Indeed MSIE will only open the file if the URL has a .mht file extension (i.e. its breaking most of the rules about HTTP).

Also, MSIE will happily load anything which contains an embedded multipart/related file (provided it is encoded as plain text) without rendering the data that the attachment is contained within. It looks like the functionality for handling these files is a quick hack to allow viewing of the files

If you reconfigure your webserver to parse .mht urls using php (or use mod_rewrite to remap the URL) then you'll probably find that it may work (although I wouldn't hold out a lot of hope of it working with a query string appended). But expect problems if you are generating dynamic content (it won't expire from the cache / refresh when you expect).

To cut a long story short - its not going to work.

symcbean
I worked for mobile browsers, not for normal desktop browsers. It worked perfectly.
mshsayem
There is some code on phpclasses which is supposed to decompose a mhtml file - but it didn't work for me :(
symcbean
+1  A: 

Here is it [worked for me] (No, I did not used PHPMailer; may be it is useful, but I could not make it working):

// Two contents : application/xhtml+xml and image/gif
// Here we go
<?php
    $boundary = "ghorar#deem";
    $im_len = filesize("path/to/abc.gif")
    header("Content-Type:multipart/related; boundary=\"$boundary\"; type=\"application/xhtml+xml\"");
    $xml_cnt = <<<EOD
<media xmlns="http://www.sth.com/sth.xsd"&gt;
    <objectURI>cid:[email protected]</objectURI>
    <size>$im_len</size>
    <type>image/gif</type>
    <name>abcxyz</name>     
    <description>blah blah</description>
</media>
EOD;
    $xml_len = strlen($xml_cnt);        
    $im = imagecreatefromgif("path/to/abc.gif");
    $to_send = "This is a multi-part message example in MIME format

--$boundary
Content-Type: application/xhtml+xml;
Content-ID: <[email protected]>
Content-Length: $xml_len

$xml_cnt
--$boundary
Content-Type: image/gif;
Content-ID: <[email protected]>
Content-Length: $im_Len
Content-Transfer-Encoding: binary

";
    echo $to_send;
    imagegif($im);
    echo "\r\n--$boundary--";
    imagedestroy($im);
?>

You can load the xml from file also. But, note that if your xml refers the image (like I did here) you need to refer that with its Content-ID. Also, note the '<' '>' characters in the Content-ID field of the image (after the boundary) and the 'cid:' notation in the place where it is referred. It worked for me. Thanks to Carlos Lima for spending time for me.

mshsayem