<?php
/*
 * PHP GenerateMIMEMail Function
 * Version 1.0 - April 2003
 * Version 2.0 - August 2005   - added attachments, boundary tweaking
 * Version 2.1 - April 2007    - added inline-attachments capability
 * Version 2.2 - April 2007    - optimised memory usage for attachments
 *                               uses half the memory it did in 2.1 which is
 *                               how it was in 2.0
 * Version 2.3 - November 2007 - added ability to pass attachment binary data
 *                               as an argument in the attachment array
 * (c) 2003,2007 Paul Gregg <pgregg@pgregg.com>
 * http://www.pgregg.com
 *
 * Function: Generate a valid MIME email with html and plain text elements
 *           and attach any files as needed
 *
 * This file should be included by other php scripts
 * 
 * Open Source Code:   If you use this code on your site for public
 * access (i.e. on the Internet) then you must attribute the author and
 * source web site: http://www.pgregg.com/projects/
 * You must also make this original source code available for download
 * unmodified or provide a link to the source.  Additionally you must provide
 * the source to any modified or translated versions or derivatives.
 *
 * This software is Donationware - if you feel you have benefited from
 * the use of this tool then please consider a donation. The value of
 * which is entirely left up to your discretion.
 * http://www.pgregg.com/donate/
 *
 */

// Function to generate a valid MIME email with html and plain text elements
// and attach any files as needed

// Usage notes:
// At a minimum you need to pass in an HTML formatted message.
// The plain text email can be supplied, or if left out (or you pass NULL)
// then strip_tags() will be called on the HTML to generate the plain text.
// Attachments:
//  In Version 2.0 - you simply passed in an array of filenames. These would
//  be encoded and attached as regular attachments to the email body.
//  In Version 2.1 - you can, optionally, provide a "string" type key to
//  the array value.  This implies that this attachment is an in-line one
//  and is encoded accordingly. This only works for images.  The HTML part
//  of the email should contain this string key as a PLACEHOLDER. The
//  placeholder text is replaced with a call to the image.
//  e.g. regular attachments:
//         $attachments = array('file1.txt', 'file2.jpg');
//       attachment + inline:
//         $attachments = array('file1.txt', 'INLINEIMAGE'=>'file2.jpg');
//         with inline images the string "INLINEIMAGE" is replaced with the
//         correct content marker to display the image inline when viewing.
//       pass attachment as variable
//         $attachments = array('file1.txt', '1:image/jpeg'=>$imagedata);
//         the key value before the : is ignored but used for uniqueness
//         the key value after the : is used for the attachment content type
//         the raw attachment data is passed by variable



function GenerateMIMEMail(
           $html, $plain=NULL, $attachments=array(), $boundarybase=NULL) {

  $CRLF = "\n"; # Check your email injector - you may need \r\n

  if (is_null($plain)) // crude, but effective if you layout the html nicely
    $plain = str_replace('&nbsp;', ' ', strip_tags($html));
    
  if (is_null($boundarybase))
    $boundarybase = '==pgregg_Multipart_Boundary';
  
  $mime_boundary1 = $boundarybase . '1_' . md5(time()); 
  $mime_boundary2 = $boundarybase . '2_' . md5(time()+1); 


  // Lets generate the email headers we are going to use
  $headers = '';

  // Add MIME headers
  $headers .= "MIME-Version: 1.0$CRLF";
  $headers .= "Content-type: multipart/mixed;$CRLF boundary=\""
            . $mime_boundary1 . '";' . "$CRLF";

  // Pre-generate the Content-ID: / cid: for the in-line attachment placeholders
  $placeholder_cid = array();
  if (is_array($attachments) && count($attachments) > 0) {
    foreach ($attachments as $placeholder => $tmpfile) {
      if (is_readable($tmpfile)) {
        if (is_string($placeholder) && strpos($placeholder, ':')===false) {
          # attachment is an inline image
          $tmpfilename = basename($tmpfile);
          $cid = uniqid() .'@'. mt_rand(100000,999999) .'-'. mt_rand(1000,9999);
          $html = preg_replace("/$placeholder/", "<img alt=\"$tmpfilename\" hspace=\"3\" src=\"cid:$cid\" align=\"baseline\" border=\"0\">", $html);
          $placeholder_cid[$placeholder] = $cid;
        }
      }
    }
  }


    
  // Now generate the body of the email
  $body = <<<EOMSG
This is a MIME message. If you are reading this text, you
might want to consider changing to a mail reader that
understands how to properly display MIME multipart messages.

--$mime_boundary1
Content-Type: multipart/alternative;
  boundary="$mime_boundary2"

--$mime_boundary2
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


EOMSG
  . $plain . <<<EOMSG


--$mime_boundary2
Content-Type: text/html
Content-Transfer-Encoding: 7bit


EOMSG
  . $html . <<<EOMSG

--$mime_boundary2--


EOMSG;


  // Calculate our MIME attachments and in-line attachments
  // Lets attach any files we were given 
  if (is_array($attachments) && count($attachments) > 0) {
    foreach ($attachments as $placeholder => $tmpfile) {
      $attachment_isfile = false;
      $attachment_israw = false;
      if (is_string($placeholder) && strpos($placeholder, ':')!==false) {
        // tmpfile argument is the raw attachment data
        list($dummy, $tmp_mimetype) = explode(':', $placeholder,2);
        $attachment_israw = true;
      } else {
        $tmpfilename = basename($tmpfile);
        if (function_exists('mime_content_type'))
          $tmp_mimetype = mime_content_type($tmpfile);
        else
          $tmp_mimetype = 'application/octet-stream';
        if (is_readable($tmpfile))
          $attachment_isfile = true;
      }
      if ($attachment_isfile || $attachment_israw) {
        if (is_string($placeholder) && strpos($placeholder, ':')===false) {
          # attachment is an inline one
          #$cid = uniqid() . '@' . mt_rand(100000,999999) . '-' . mt_rand(1000,9999);
          # Recover the previously generated Content-ID: for this attachment
          $cid = $placeholder_cid[$placeholder];
          $body .= sprintf("--%s\nContent-Type: %s\n name=%s\nContent-Transfer-Encoding: base64\nContent-ID: <%s>\nContent-Description: %s\nContent-Location: %s\n\n",
            $mime_boundary1, $tmp_mimetype, $tmpfilename,
            $cid, $tmpfilename, $tmpfilename );
        } else {
          $body .= sprintf("--%s\nContent-Type: %s\n name=%s\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment;\n filename=\"%s\"\n\n",
            $mime_boundary1, $tmp_mimetype, $tmpfilename, $tmpfilename );
        }
        if ($attachment_isfile)
          $tmpfile = file_get_contents($tmpfile);
        $body .= chunk_split(base64_encode($tmpfile)) . "\n"; 
      }
    }
  }

  // Terminate the outer MIME boundary
  $body .= '--' . $mime_boundary1 . "--\n";

  // We now have our headers, body and attachments correctly encoded

  return array($headers, $body);
}
?>