diff options
author | Andreas Gohr <andi@splitbrain.org> | 2011-11-02 08:59:18 +0100 |
---|---|---|
committer | Andreas Gohr <andi@splitbrain.org> | 2011-11-02 08:59:18 +0100 |
commit | bb01c27c6c2c8e83091764cebadeef0489985b4b (patch) | |
tree | 92d876362c05c23623c241d42c5da4b804bcbb24 | |
parent | 222298bcee7f8e8fd98bb6fc1bcfb821ac1e55cd (diff) | |
download | rpg-bb01c27c6c2c8e83091764cebadeef0489985b4b.tar.gz rpg-bb01c27c6c2c8e83091764cebadeef0489985b4b.tar.bz2 |
Added Mailer class
-rw-r--r-- | inc/Mailer.class.php | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/inc/Mailer.class.php b/inc/Mailer.class.php new file mode 100644 index 000000000..991ec6c3e --- /dev/null +++ b/inc/Mailer.class.php @@ -0,0 +1,324 @@ +<?php +/** + * @author Andreas Gohr <andi@splitbrain.org> + */ + + +// end of line for mail lines - RFC822 says CRLF but postfix (and other MTAs?) +// think different +if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL',"\n"); +#define('MAILHEADER_ASCIIONLY',1); + + +class Mailer { + + private $headers = array(); + private $attach = array(); + private $html = ''; + private $text = ''; + + private $boundary = ''; + private $partid = ''; + private $sendparam= ''; + + function __construct(){ + $this->partid = md5(uniqid(rand(),true)).'@'.$_SERVER['SERVER_NAME']; + $this->boundary = '----------'.md5(uniqid(rand(),true)); + } + + /** + * Attach a file + * + * @param $path Path to the file to attach + * @param $mime Mimetype of the attached file + * @param $name The filename to use + * @param $embed Unique key to reference this file from the HTML part + */ + public function attachFile($path,$mime,$name='',$embed=''){ + if(!$name){ + $name = basename($path); + } + + $this->attach[] = array( + 'data' => file_get_contents($path), + 'mime' => $mime, + 'name' => $name, + 'embed' => $embed + ); + } + + /** + * Attach a file + * + * @param $path The file contents to attach + * @param $mime Mimetype of the attached file + * @param $name The filename to use + * @param $embed Unique key to reference this file from the HTML part + */ + public function attachContent($data,$mime,$name='',$embed=''){ + if(!$name){ + list($junk,$ext) = split('/',$mime); + $name = count($this->attach).".$ext"; + } + + $this->attach[] = array( + 'data' => $data, + 'mime' => $mime, + 'name' => $name, + 'embed' => $embed + ); + } + + /** + * Set the HTML part of the mail + * + * Placeholders can be used to reference embedded attachments + */ + public function setHTMLBody($html){ + $this->html = $html; + } + + /** + * Set the plain text part of the mail + */ + public function setTextBody($text){ + $this->text = $text; + } + + /** + * Ses an email address header with correct encoding + * + * Unicode characters will be deaccented and encoded base64 + * for headers. Addresses may not contain Non-ASCII data! + * + * Example: + * setAddress("föö <foo@bar.com>, me@somewhere.com","TBcc"); + * + * @param string $address Multiple adresses separated by commas + * @param string $header Name of the header (To,Bcc,Cc,...) + */ + function mail_encode_address($address,$header){ + // No named recipients for To: in Windows (see FS#652) + $names = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? false : true; + + $headers = ''; + $parts = explode(',',$address); + foreach ($parts as $part){ + $part = trim($part); + + // parse address + if(preg_match('#(.*?)<(.*?)>#',$part,$matches)){ + $text = trim($matches[1]); + $addr = $matches[2]; + }else{ + $addr = $part; + } + // skip empty ones + if(empty($addr)){ + continue; + } + + // FIXME: is there a way to encode the localpart of a emailaddress? + if(!utf8_isASCII($addr)){ + msg(htmlspecialchars("E-Mail address <$addr> is not ASCII"),-1); + continue; + } + + if(!mail_isvalid($addr)){ + msg(htmlspecialchars("E-Mail address <$addr> is not valid"),-1); + continue; + } + + // text was given + if(!empty($text) && $names){ + // add address quotes + $addr = "<$addr>"; + + if(defined('MAILHEADER_ASCIIONLY')){ + $text = utf8_deaccent($text); + $text = utf8_strip($text); + } + + if(!utf8_isASCII($text)){ + //FIXME + // put the quotes outside as in =?UTF-8?Q?"Elan Ruusam=C3=A4e"?= vs "=?UTF-8?Q?Elan Ruusam=C3=A4e?=" + /* + if (preg_match('/^"(.+)"$/', $text, $matches)) { + $text = '"=?UTF-8?Q?'.mail_quotedprintable_encode($matches[1], 0).'?="'; + } else { + $text = '=?UTF-8?Q?'.mail_quotedprintable_encode($text, 0).'?='; + } + */ + $text = '=?UTF-8?B?'.base64_encode($text).'?='; + } + }else{ + $text = ''; + } + + // add to header comma seperated + if($headers != ''){ + $headers .= ','; + $headers .= MAILHEADER_EOL.' '; // avoid overlong mail headers + } + $headers .= $text.' '.$addr; + } + + if(empty($headers)) return false; + + $this->headers[$header] = $headers; + return $headers; + } + + /** + * Add the To: recipients + * + * @see setAddress + * @param string $address Multiple adresses separated by commas + */ + public function to($address){ + $this->setAddress($address, 'To'); + } + + /** + * Add the Cc: recipients + * + * @see setAddress + * @param string $address Multiple adresses separated by commas + */ + public function cc($address){ + $this->setAddress($address, 'Cc'); + } + + /** + * Add the Bcc: recipients + * + * @see setAddress + * @param string $address Multiple adresses separated by commas + */ + public function bcc($address){ + $this->setAddress($address, 'Bcc'); + } + + /** + * Add the mail's Subject: header + * + * @param string $subject the mail subject + */ + public function subject($subject){ + if(!utf8_isASCII($subject)){ + $subject = '=?UTF-8?B?'.base64_encode($subject).'?='; + } + $this->headers['Subject'] = $subject; + } + + /** + * Prepare the mime multiparts for all attachments + * + * Replaces placeholders in the HTML with the correct CIDs + */ + protected function prepareAttachments(){ + $mime = ''; + $part = 1; + // embedded attachments + foreach($this->attach as $media){ + // create content id + $cid = 'part'.$part.'.'.$this->partid; + + // replace wildcards + if($media['embed']){ + $this->html = str_replace('%%'.$media['embed'].'%%','cid:'.$cid,$this->html); + } + + $mime .= '--'.$this->boundary.MAILHEADER_EOL; + $mime .= 'Content-Type: '.$media['mime'].';'.MAILHEADER_EOL; + $mime .= 'Content-Transfer-Encoding: base64'.MAILHEADER_EOL; + $mime .= "Content-ID: <$cid>".MAILHEADER_EOL; + if($media['embed']){ + $mime .= 'Content-Disposition: inline; filename="'.$media['name'].'"'.MAILHEADER_EOL; + }else{ + $mime .= 'Content-Disposition: attachment; filename="'.$media['name'].'"'.MAILHEADER_EOL; + } + $mime .= MAILHEADER_EOL; //end of headers + $mime .= chunk_split(base64_encode($media['data']),74,MAILHEADER_EOL); + + $part++; + } + return $mime; + } + + protected function createBody(){ + // check for body + if(!$this->text && !$this->html){ + return false; + } + + // add general headers + $this->headers['MIME-Version'] = '1.0'; + + if(!$this->html && !count($this->attach)){ // we can send a simple single part message + $this->headers['Content-Type'] = 'text/plain; charset=UTF-8'; + $this->headers['Content-Transfer-Encoding'] = 'base64'; + $body = chunk_split(base64_encode($this->text),74,MAILHEADER_EOL); + }else{ // multi part it is + + // prepare the attachments + $attachments = $this->prepareAttachments(); + + // do we have alternative text content? + if($this->text && $this->html){ + $this->headers['Content-Type'] = 'multipart/alternative; boundary="'.$this->boundary.'XX"'; + $body = "This is a multi-part message in MIME format.".MAILHEADER_EOL; + $body .= '--'.$this->boundary.'XX'.MAILHEADER_EOL; + $body .= MAILHEADER_EOL; + $body .= 'Content-Type: text/plain; charset=UTF-8'; + $body .= 'Content-Transfer-Encoding: base64'; + $body .= chunk_split(base64_encode($this->text),74,MAILHEADER_EOL); + $body .= '--'.$this->boundary.'XX'.MAILHEADER_EOL; + $body .= 'Content-Type: multipart/related; boundary="'.$this->boundary.'"'.MAILHEADER_EOL; + $body .= MAILHEADER_EOL; + }else{ + $this->headers['Content-Type'] = 'multipart/related; boundary="'.$this->boundary.'"'; + $body = "This is a multi-part message in MIME format.".MAILHEADER_EOL; + } + + $body .= '--'.$this->boundary."\n"; + $body .= "Content-Type: text/html; charset=UTF-8\n"; + $body .= "Content-Transfer-Encoding: base64\n"; + $body .= MAILHEADER_EOL; + $body = chunk_split(base64_encode($this->html),74,MAILHEADER_EOL); + $body .= MAILHEADER_EOL; + $body .= $attachments; + $body .= '--'.$this->boundary.'--'.MAILHEADER_EOL; + + // close open multipart/alternative boundary + if($this->text && $this->html){ + $body .= '--'.$this->boundary.'XX--'.MAILHEADER_EOL; + } + } + + return $body; + } + + /** + * Create a string from the headers array + */ + protected function prepareHeaders(){ + $headers = ''; + foreach($this->headers as $key => $val){ + $headers .= "$key: $val".MAILHEADER_EOL; + } + return $headers; + } + + /** + * return a full email with all headers + * + * This is mainly for debugging and testing + */ + public function dump(){ + $headers = $this->prepareHeaders(); + $body = $this->prepareBody(); + + return $headers.MAILHEADER_EOL.$body; + } +} |