<?php
/**
 * e_mail
 *
 * A small class to handle mail-creation an -sending
 * It supports text and html-mails (and both) and 
 * can handle attachments.
 *
 * e_mail::parse_template can process mail-templates and 
 * substitude templatetags with given data.
 *
 * @author Matthias Viehweger <matthias.viehweger@kronn.de>
 * @version 0.3
 * @license MIT-License
 */
class e_mail {
	/**
	 * variables
	 */
	var $text = FALSE;
	var $html = FALSE;
	var $attachments = FALSE;

	var $config;

	/**
	 * storage for error-messages
	 */
	var $error;

	/**
	 * data-parts of e-mail
	 */
	var $message_header;
	var $message_body;

	/**
	 * contructor
	 */
	function e_mail() {
		ini_set('track_errors', '1');
	}

	/**
	 * set configuration
	 *
	 * @param string $to
	 * @param string $from
	 * @param string $topic
	 * @param string $replyto [optional]
	 */
	function set_config($to, $from, $topic, $replyto='') {
		$this->config = array(
			'to'=>$to,
			'from'=>$from,
			'topic'=>$topic
		);

		if ( $replyto != '' ) $this->config['replyto'] = $replyto;
	}

	/**
	 * get last error-message
	 */
	function get_error() {
		return array_pop($this->error);
	}

	/**
	 * check wether it has to be a mime-mail or not
	 *
	 * @return boolean
	 */
	function must_be_mime() {
		$must_be_mime = FALSE;

		if ( $this->html != FALSE 
			OR $this->attachments != FALSE) {
			$must_be_mime = TRUE;
		}

		return $must_be_mime;
	}

	/**
	 * set text-part
	 */
	function set_text($txt) {
		$this->text = (string) $txt;
	}
	/**
	 * set html-part
	 */
	function set_html($html) {
		$this->html = (string) $html;
	}

	/**
	 * add an attachment
	 *
	 * @param string  $filename
	 * @param string  $mime     [optional]
	 * @return boolean
	 */
	function add_attachment($filename, $mime='') {
		if ( empty($filename) ) {
			$this->error[] = 'No Filename provided';
			return FALSE;
		}
		if ( !is_file($filename) ) {
			$this->error[] = $filename . ' not found.';
			return FALSE;
		}

		if ( $mime == '') {
			// trying to find the mime-type
			if ( function_exists('mime_content_type') ) {
				$mime = mime_content_type($filename);
			} else {
				$this->error[] = 'No mime-type provided and unable to guess it.';
				return FALSE;
			}
		}

		// saving the data
		$file = array(
			'name'=>$filename,
			'mime'=>$mime
		);

		if ( $this->attachments === FALSE ) {
			$this->attachments = array();
		}

		$this->attachments[] = $file;

		return TRUE;
	}

	/**
	 * unset vars
	 */
	function clean_vars() {
		$this->text = FALSE;
		$this->html = FALSE;
		$this->attachments = FALSE;
	}

	/**
	 * parse template
	 *
	 * The template is filled with data. For every key in the 
	 * data-array, a substitution is attempted.
	 *
	 * {NAME} will be replaced with $data['name']
	 *
	 * All remaining templatetags will be removed.
	 *
	 * The resulting string will be returned.
	 *
	 * @param string $template
	 * @param array $data
	 * @return string
	 */
	function parse_template($template, $data) {
		$content = $template;

		// substitute templatetags
		foreach( $data as $key => $value) {
			$content = str_replace('{'.strtoupper($key).'}', $value, $content);
		}

		// discard unused templatetags
		$content = preg_replace('/{[-_a-z]*}/i', '', $content);

		return $content;
	}

	/**
	 * composition of mail-headers and body
	 *
	 * the e-mail-composition consists of the following steps:
	 *
	 * - Check wether (or not) a mime-mail is necessary, if yes:
	 *   - check if attachments have to be handled, if yes:
	 *     - set header to multipart/mixed
	 *     - generate and add outer boundary
	 *   - set header to multipart/alternative and generate boundary
	 *   - plaintext-part generate if none set.
	 *   - compose body
	 *   - mark end of body
	 *   - check if attachments have to be handled, if yes:
	 *     - add attachments and boundaries
	 *     - mark end of mail
	 *
	 * - always:
	 *   - save header in message_header
	 *   - save body in message_body
	 *   - clean temporary variables
	 */
	function compose_message() {
		$headers[] = 'From: '.$this->config['from'];
		if ( isset($this->config['replyto']) ) $headers[] = 'Reply-To: '.$this->config['replyto'];

		if ( $this->must_be_mime() ) {
			$headers[] = 'MIME-Version: 1.0';
			$boundary = md5(uniqid(date('d.m.Y \u\m H:i',mktime() )));

			if ( $this->attachments != FALSE ) {
				//tell e-mail client this e-mail contains more than one part
				$headers[] = 'Content-Type: multipart/mixed; boundary="main'.$boundary."\"\r\n";
				$headers[] = '--main'.$boundary;
			}
			//tell e-mail client this e-mail contains alternate versions
			$headers[] = 'Content-Type: multipart/alternative; boundary="sub'.$boundary."\"\r\n";

			//plain text part of message
			if ( empty($this->text) ) {
				$this->text = strip_tags($this->html); 
			}
			$body = '--sub'.$boundary."\r\n" .
				"Content-Type: text/plain; charset=ISO-8859-1\r\n" .
				"Content-Transfer-Encoding: base64\r\n\r\n";
			$body .= chunk_split(base64_encode($this->text));

			//html part of message
			$body .= "\r\n\r\n".'--sub'.$boundary."\r\n" .
				"Content-Type: text/html; charset=ISO-8859-1\r\n" .
				"Content-Transfer-Encoding: base64\r\n\r\n";
			$body .= chunk_split(base64_encode($this->html));

			//end of message
			$body .= "\r\n".'--sub'.$boundary."--\r\n\r\n.";

			if ($this->attachments != FALSE ) {
				//attachments of message
				$files = $this->attachments;

				foreach ( $files as $file ) {
					$body .= "\r\n--main".$boundary."\r\n".
						"Content-Type: " . $file['mime']. "\r\n" .
						"Content-Transfer-Encoding: base64\r\n" .
						"Content-Disposition:attachment\r\n\r\n";
					$body .= chunk_split(base64_encode( file_get_contents($file['name']) ));
				}
				$body .= '--main'.$boundary."--\r\n\r\n.";
			}

		} else {
			$body = $this->text;

		}

		$this->message_body = $body;
		$this->message_header = implode("\r\n", $headers);

		$this->clean_vars();
	}

	/**
	 * send mail
	 */
	function send_mail() {
		if ( empty($this->message_body) 
			OR empty($this->message_header) 
			OR empty($this->config) 
		) {
			$this->error[] = 'Unvollständige Daten';
			return FALSE;
		}

		$mailed = @mail(
				$this->config['to'], 
				$this->config['topic'], 
				$this->message_body, 
				$this->message_header
			) OR $this->error[] = $php_errormsg;

		return $mailed;
	}

	/**
	 * send an email
	 *
	 * @param array $data    Array with the following keys:
	 *                       - text   messagebody as text/plain
	 *                       - html   messagebody as text/html
	 *                       - css    CSS for the HTML-part
	 * @param array $config  Array with the following keys:
	 *                       - mailfrom
	 *                       - replyto
	 *                       - mailtopic
	 *                       - mailreceipient
	 */
	function compose_and_send($data, $config) {
		$headers  = 'From: '.$config['mailfrom']."\r\n";
		$headers .= 'Reply-To: '.$config['replyto']."\r\n";
		$headers .= 'MIME-Version: 1.0'."\r\n";

		$boundary = md5(uniqid(date('d.m.Y \u\m H:i',mktime() )));

		//tell e-mail client this e-mail contains//alternate versions
		$headers .= 'Content-Type: multipart/alternative; boundary="'.$boundary."\"\r\n\r\n";

		$content = $data['text'];

		$htmlcontent = '<html><head><title>'.$config['mailtopic'].'</title>'."\n".'<style>'."\n";
		$htmlcontent .= $data['css'];
		$htmlcontent .= '</style>'."\n".'</head><body><div id="mailwrapper">'."\n";
		$htmlcontent .= $data['html'];
		$htmlcontent .= "\n".'</div></body></html>';

		//plain text part of message
		$body = '--'.$boundary."\r\n" .
			"Content-Type: text/plain; charset=ISO-8859-1\r\n" .
			"Content-Transfer-Encoding: base64\r\n\r\n";
		$body .= chunk_split(base64_encode($content));

		//html part of message
		$body .= "\r\n\r\n".'--'.$boundary."\r\n" .
			"Content-Type: text/html; charset=ISO-8859-1\r\n" .
			"Content-Transfer-Encoding: base64\r\n\r\n";
		$body .= chunk_split(base64_encode($htmlcontent));

		//end of message
		$body .= "\r\n".'--'.$boundary."--\r\n\r\n.";

		$mailed = ( mail($config['mailreceipient'], $config['mailtopic'], $body, $headers) )? TRUE: FALSE;

		return($mailed);
	}
}
?>
