PHP Demo Application - Source Code
/Framework/Model/Libraries/Email.php
<?php
/**
* Script Contents: Apeel_Framework_Model_Libraries_Email Class Library
* @package Apeel_Framework_Model_Libraries
*/
/**
* Library to provide Email Sending and Verification functionality. Supports
* attachments and embedded images.
*
* Verification (which is optional) works by looking up the MX (Mail Exchange)
* records of the domain of the email address supplied. This can be useful
* for warning the user if they have mis-typed their email address for example.
*
* Embedding images gets around the issue of blocked images in popular email
* clients such as Outlook.
*
* It uses the standard PHP mail command to actually send the email - if you
* require other methods of delivery have a look at PHPMailer:
* http://phpmailer.worxware.com/
*
* @package Apeel_Framework_Model_Libraries
* @version 1.1.0
* @author John W. King (email: contact@apeelframework.net)
* @copyright City Business Logic Limited 2001-2011
* @license Dual MIT / GNU Lesser General Public License Version 3
*/
class Apeel_Framework_Model_Libraries_Email
{
/**
* The email address that the email is to be sent from.
*
* @var string
*/
public $senderAddress = NULL;
/**
* The name of the person/organisation sending the email.
*
* @var string
*/
public $senderName = NULL;
/**
* The email address the email is to be sent to.
*
* @var string
*/
public $recipientAddress = NULL;
/**
* The name of the person/organisation the email is being sent to.
*
* @var string
*/
public $recipientName = NULL;
/**
* The email subject line.
*
* @var string
*/
public $subject = NULL;
/**
* The email message in plain text format.
*
* @var string
*/
public $_messageText = NULL;
/**
* The email message in HTML format.
*
* @var string
*/
public $_messageHtml = NULL;
/**
* Contains a list of CID (Unique ID used for embedded images) and matching
* image filenames for image embedding.
*
* @var array
*/
private $_imageFiles = NULL;
/**
* The random hash used to seperate the parts in a multi-part email.
*
* @var string
*/
private $_randomHash = NULL;
/**
* Collection of Files to be attached to the email.
*
* @var array
*/
private $_fileAttachments = NULL;
/**
* Collection of Image Files to be embedded into the email.
*
* @var array
*/
private $_imageAttachments = NULL;
// Constants
const CRLF = "\r\n";
const CR = "\n";
/**
* Constructor resets timezone to prevent strict mode errors, and generates
* the random hash based on the time.
*
* @return void
*/
function __construct() {
// Make sure timezone is set to prevent warnings, set reply address and generate Unique Hash.
date_default_timezone_set('Europe/London');
$this->_randomHash = md5(date('r', time()));
}
/**
* Sends the email.
*
* Please ensure all values are correctly set before calling this method.
*
* Address Validation is useful if for example the user has typed in their
* email address which may be prone to mis-typing. If it is not required
* then the $doAddressValidation parameter should be set to false (default)
* to speed up the process of sending the mail.
*
* @param boolean $doAddressValidation
* @return boolean
*/
public function sendEmail($doAddressValidation = false) {
// Validate recipient address if requested to do so.
$emailValid = true;
if ($doAddressValidation) {
if (!$this->validateEmailAddress()) {
$emailValid = false;
}
}
if ($emailValid) {
if (($this->_messageHtml == "") && (!$this->_fileAttachments) && (!$this->_imageAttachments)) {
// Generate Text Email
// Set Header
$mailHeader = $this->generateMailHeader(false);
// Generate Email
$mailBody = $this->generateEmail(false);
} else {
// Generate Multipart Email
// Set Header
$mailHeader = $this->generateMailHeader(true);
// Generate Email
$mailBody = $this->generateEmail(true);
}
// Send Email
if (!@mail($this->recipientAddress, $this->subject, $mailBody, $mailHeader)) {
$emailValid = false;
}
}
return $emailValid;
}
/**
* Constructs message body from the component parts.
*
* @param string $textMessage
* @param string $htmlMessage
* @return void
*/
protected function setMessageBody($textMessage, $htmlMessage = '') {
$this->_messageText = $textMessage;
$this->_messageHtml = $htmlMessage;
$this->_fileAttachments = NULL;
$this->_imageAttachments = NULL;
$this->_imageFiles = NULL;
}
/**
* Method used to validate the recipient email address.
*
* Uses the checkdnsrr function if available, otherwise uses winCheckDnsRr
* if running on a windows box.
*
* @return boolean
*/
protected function validateEmailAddress() {
// Validate email using checkdnsrr if it is available, otherwise use Windows version
if (strpos($this->recipientAddress, "@")) {
list($user, $domain) = explode('@', $this->recipientAddress);
if (function_exists('checkdnsrr')) {
return checkdnsrr($domain, 'MX');
} else {
return $this->winCheckDnsRr($domain, 'MX');
}
} else {
return false;
}
}
/**
* Calls Windows nslookup function to check existance of MX DNS records for
* supplied host. Called by validateEmailAddress when checkdnsrr is not
* available.
*
* @param string $host
* @param string $type
* @return boolean
*/
private function winCheckDnsRr($host, $type=''){
if(!empty($host)){
$type = (empty($type)) ? 'MX' : $type;
exec('nslookup -type='.$type.' '.escapeshellcmd($host), $result);
$it = new ArrayIterator($result);
if (RegexIterator) {
foreach(new RegexIterator($it, '~^'.$host.'~', RegexIterator::GET_MATCH) as $result){
if($result){
return true;
}
}
}
}
return false;
}
/**
* Attaches a file to the email.
*
* Encodes the binary of the file to base64 and generates the appropriate
* email part.
*
* @param string $filename
* @param string $mimeType
* @return void
*/
public function attachFile($filename, $mimeType) {
$fileContents = @chunk_split(base64_encode(@file_get_contents($filename)));
$fileAttachment = '--PHP-mixed-' . $this->_randomHash . self::CR;
$fileAttachment .= 'Content-Type: ' . $mimeType . '; name="' . $filename . '"' . self::CR;
$fileAttachment .= 'Content-Transfer-Encoding: base64' . self::CR;
$fileAttachment .= 'Content-Disposition: attachment' . self::CR;
$fileAttachment .= self::CR;
$fileAttachment .= $fileContents . self::CR;
$this->_fileAttachments .= $fileAttachment;
}
/**
* Attaches an image file to the email for embedding.
*
* Encodes the binary of the file to base64 and generates the appropriate
* email part.
*
* A random CID unique ID is generated and added to the _imageFiles array
* for later replacement in the actual HTML image tags of the email.
*
* @param string $filename
* @param string $mimeType
* @return void
*/
public function attachInlineImage($filename, $mimeType) {
$Cid = md5(md5(date('r', time())) . 'image');
$fileContents = @chunk_split(base64_encode(@file_get_contents($filename)));
$imageAttachment = '--PHP-mixed-' . $this->_randomHash . self::CR;
$imageAttachment .= 'Content-Type: ' . $mimeType . '; name="' . $filename . '"' . self::CR;
$imageAttachment .= 'Content-Transfer-Encoding: base64' . self::CR;
$imageAttachment .= 'Content-ID: <' . $Cid . '>' . self::CR;
$imageAttachment .= 'Content-Disposition: inline; filename=' . $Cid . self::CR;
$imageAttachment .= self::CR;
$imageAttachment .= $fileContents . self::CR;
$this->_imageAttachments .= $imageAttachment;
$this->_imageFiles[$Cid] = basename($filename);
}
/**
* Generates Formatted Email Header
*
* @param boolean $multiPart
* @return string
*/
private function generateMailHeader($multiPart) {
if ($this->senderName == '') {
$this->senderName = $this->senderAddress;
}
$fromAddress = $this->senderName . '<' . $this->senderAddress . '>';
ini_set('sendmail_from', $fromAddress);
$mailHeader = 'From: ' . $fromAddress . self::CRLF;
$mailHeader .= 'Reply-To: ' . $fromAddress . self::CRLF;
if ($multiPart) {
$mailHeader .= 'Content-Type: multipart/mixed; boundary="PHP-mixed-' . $this->_randomHash . '"';
}
return $mailHeader;
}
/**
* Generates Email from compenent parts.
*
* @param boolean $multiPart
* @return string
*/
private function generateEmail($multiPart) {
// Generate Email Body
if ($multiPart) {
$email = '--PHP-mixed-' . $this->_randomHash . self::CR;
$email .= 'Content-Type: multipart/alternative; boundary="PHP-alt-' . $this->_randomHash . '"' . self::CR;
$email .= self::CR;
$email .= '--PHP-alt-' . $this->_randomHash . self::CR;
$email .= 'Content-Type: text/plain; charset="iso-8859-1"' . self::CR;
$email .= 'Content-Transfer-Encoding: 7bit' . self::CR;
$email .= self::CR;
$email .= $this->_messageText . self::CR;
$email .= self::CR;
if ($this->_messageHtml != '') {
// Replace embedded images with cid:hashname syntax
if ($this->_imageFiles) {
foreach($this->_imageFiles as $index => $filename) {
$this->_messageHtml = str_replace($filename, 'cid:' . $index, $this->_messageHtml);
}
}
$email .= '--PHP-alt-' . $this->_randomHash . self::CR;
$email .= 'Content-Type: text/html; charset="iso-8859-1"' . self::CR;
$email .= 'Content-Transfer-Encoding: 7bit' . self::CR;
$email .= self::CR;
$email .= $this->_messageHtml . self::CR;
$email .= self::CR;
}
$email .= '--PHP-alt-'. $this->_randomHash . '--' . self::CR;
$email .= $this->_fileAttachments;
$email .= $this->_imageAttachments;
} else {
$email = $this->messageText;
}
return $email;
}
}
?>