<?php
/*=====================================================================*\
|| ###################################################################
|| # Blue Static ISSO Framework
|| # Copyright (c)2005-2009 Blue Static
|| #
|| # This program is free software; you can redistribute it and/or modify
|| # it under the terms of the GNU General Public License as published by
|| # the Free Software Foundation; version 2 of the License.
|| #
|| # This program is distributed in the hope that it will be useful, but
|| # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|| # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|| # more details.
|| #
|| # You should have received a copy of the GNU General Public License along
|| # with this program; if not, write to the Free Software Foundation, Inc.,
|| # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|| ###################################################################
\*=====================================================================*/
/**
* Mail Sender (mail.php)
*
* @package ISSO
*/
require_once(ISSO . '/Functions.php');
/**
* Mail Sender
*
* This framework is a wrapper for the PHP mail function that properly
* sends mail with full email headers.
*
* @author Blue Static
* @copyright Copyright (c)2005 - 2009, Blue Static
* @package ISSO
*
*/
class BSMail
{
/**
* The subject of the message
* @var string
*/
private $subject = '';
/**
* Body plain-text of the message
* @var string
*/
private $bodyText = '';
/**
* HTML multi-part body of the message
* @var string
*/
private $bodyHtml = '';
/**
* The message sender's email address
* @var string
*/
private $from = '';
/**
* The message sender's display name
* @var string
*/
private $fromName = '';
/**
* Additional message headers
* @var string
*/
private $headers = '';
/**
* The new line delimiter used in the message
* @var string
* @access private
*/
private $delim = "\n";
/**
* Character set used to send messages with
* @var string
* @access public
*/
private $charset = 'utf-8'; // should we be using iso-8859-1 ?
/**
* Constructor
*/
public function __construct()
{
if (!BSApp::$input instanceof BSInput)
{
throw new Exception('BSApp::$input is not an instance of BSInput');
}
}
/**
* Sets the subject
*
* @param string Subject text
*/
public function setSubject($subject)
{
$this->subject = $subject;
}
/**
* Sets the body text (required)
*
* @param string Body text
*/
public function setBodyText($body)
{
$this->bodyText = $body;
}
/**
* Sets the HTML body (optional)
*
* @param string Body HTML
*/
public function setBodyHtml($body)
{
$this->bodyHtml = $body;
}
/**
* Sets the from address
*
* @param string Sending email address
*/
public function setFromAddress($address)
{
$this->from = $address;
}
/**
* Sets the from display name
*
* @param string From name
*/
public function setFromName($name)
{
$this->fromName = $name;
}
/**
* Sets any additional headers
*
* @param string Additional headers separated by a \n
*/
public function setHeaders($headers)
{
$this->headers = $headers;
}
/**
* Sets the character set to send the email in
*
* @param string Charset
*/
public function setCharset($charset)
{
$this->charset = $charset;
}
/**
* Sends an email to the specified address with the specified
* sender, subject, and body.
*
* @param string Email address to send to
* @param string Name of the recipient
* @param bool Send an HTML multipart (if HTML body specified)?
*
* @return bool Status of the message
*/
public function send($address, $name = null, $sendhtml = false)
{
if (empty($address))
{
throw new Exception('You need to specify an email address');
}
// make sure we have a mailer
// TODO - add support for SMTP
if (!@ini_get('sendmail_path'))
{
BSApp::debug("BSMail: no sendmail -> not sending");
return false;
}
// sort out the to addresses
$address = $this->_fetchFirstLine($address);
$address = trim(BSApp::$input->unsanitize($address));
$name = $this->_fetchFirstLine($name);
$name = trim(BSApp::$input->unsanitize($name));
$tostring = ($name == null ? $address : "\"$name\" <$address>");
// sanitize the from field
$from = $this->_fetchFirstLine($this->from);
$from = trim(BSApp::$input->unsanitize($from));
if (empty($from))
{
throw new Exception('You need to specify a from email address');
}
// sanitize the from name
$fromName = $this->_fetchFirstLine($this->fromName);
$fromName = ($fromName == '' ? $from : trim(BSApp::$input->unsanitize($fromName)));
$fromName = $this->_encodeHeaderValue($this->fromName);
// sanitize the subject
$subject = $this->_fetchFirstLine($this->subject);
$subject = trim(BSApp::$input->unsanitize($subject));
if (empty($subject))
{
throw new Exception('You need to specify a subject for the message');
}
// sanitize the body
$bodyText = BSFunctions::convert_line_breaks($this->bodyText, $this->delim);
$bodyText = trim(BSApp::$input->unsanitize($bodyText, true));
if (empty($bodyText))
{
throw new Exception('You need to specify body text before sending the message');
}
// attach additional headers
$headers = BSFunctions::convert_line_breaks($this->headers, $this->delim);
$headers .= ((!preg_match("#{$this->delim}$#", $headers) && $headers != '') ? "\n" : '') . "From: \"{$fromName}\" <{$from}>" . $this->delim;
$headers .= "Return-Path: {$from}" . $this->delim;
$headers .= "X-Mailer: ISSO Mail Framework" . $this->delim;
$headers .= "MIME-Version: 1.0" . $this->delim;
// see if we need to use mime/multipart
if ($sendhtml && !empty($bodyhtml) == true)
{
require_once ISSO . '/Functions.php';
$boundary = 'ISSO-MULTIPART-' . BSFunctions::random(10);
$headers .= "Content-Type: multipart/alternative; boundary=\"$boundary\"" . $this->delim;
$bodyHtml = BSFunctions::convert_line_breaks($this->bodyHtml, $this->delim);
// first part of the message (plaintext)
$body = "--$boundary" . $this->delim;
$body .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->delim;
$body .= "Content-Transfer-Encoding: 8bit" . $this->delim . $this->delim;
$body .= $bodyText . $this->delim;
// add some space between the parts
$body .= $this->delim . $this->delim . $this->delim;
// second part (html)
$body .= "--$boundary" . $this->delim;
$body .= "Content-Type: text/html; charset=\"" . $this->charset . "\"" . $this->delim;
$body .= "Content-Transfer-Encoding: 8bit" . $this->delim;
$body .= "Content-Disposition: inline" . $this->delim . $this->delim;
$body .= $bodyHtml . $this->delim;
$body .= "--$boundary--";
}
else
{
$headers .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->delim;
$body = $bodyText;
}
$headers .= "Content-Transfer-Encoding: 8bit" . $this->delim;
$headers = trim($headers);
// attempt to send the mail!
if (mail($tostring, $subject, $body, $headers, "-f {$from}"))
{
BSApp::debug("BSMail: sent to $address");
}
else
{
BSApp::debug("BSMail: error sending to $address");
}
}
/**
* Fetches the first line of a string
*
* @param string A string
*
* @return string The first line of the string
*/
private function _fetchFirstLine($string)
{
$string = BSFunctions::convert_line_breaks($string);
$broken = explode("\n", $string);
return $broken[0];
}
/**
* Encodes a header value (to name, fron name, subject, etc.) according
* to RFC 2047
*
* @param string The text to encode
*
* @return string Encoded text
*/
function _encodeHeaderValue($text)
{
if (preg_match('#[^a-zA-Z0-9\+\-\*!/]#', $text) == 0)
{
return $text;
}
// perform this on non-ASCII characters; excluding _ and = because we want them to be encoded as they have
// different meanings in mail messages
$text = preg_replace('#([^a-zA-Z0-9\+\-\*!/])#e', '"=" . strtoupper(dechex(ord("\\1")))', $text);
$text = str_replace('=20', '_' , $text);
return '=?' . $this->charset . '?q?' . $text . '?=';
}
}
?>