| // +----------------------------------------------------------------------+ // // $Id: vlibMimeMail.php 1438 2006-10-29 13:26:42Z b4rt $ // check to avoid multiple including of class if (!defined('vlibMimeMailClassLoaded')) { define('vlibMimeMailClassLoaded', 1); // get the functionality of the vlibCommon class. include_once(dirname(__FILE__).'/vlibCommon/common.php'); // get error reporting functionality. include_once(dirname(__FILE__).'/vlibMimeMail/error.php'); /** * vlibMimeMail Class is used send mime encoded mail messages. * For instructions on how to use vlibMimeMail, see the * vlibMimeMail.html file, located in the 'docs' directory. * * @since 22/04/2002 * @author Kelvin Jones * @package vLIB * @access public * @see vlibMimeMail.html */ class vlibMimeMail { /*-----------------------------------------------------------------------------\ | ATTENTION | | Do not touch the following variables. vlibTemplate will not work otherwise. | \-----------------------------------------------------------------------------*/ /** lists To addresses */ var $sendto = array(); /** lists Cc addresses */ var $sendcc = array(); /** lists Bcc addresses */ var $sendbcc = array(); /** paths of attached files */ var $attachments = array(); /** attachment mime-types */ var $mimetypes = array(); /** attachment dispositions */ var $dispositions = array(); /** attachment content IDs */ var $contentIDs = array(); /** list of message headers */ var $xheaders = array(); /** message priorities */ var $priorities = array( '1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)' ); /** character set of plain text message */ var $charset = "us-ascii"; var $ctencoding = "7bit"; /** character set of html message */ var $htmlcharset = "us-ascii"; var $htmlctencoding = "7bit"; /** Request receipt?? */ var $receipt = 0; /** Do we need to encode when we send?? */ var $doencoding = 0; /** whether to try and fix the windows bug fix */ var $apply_windows_bugfix = false; var $all_emails = array(); // if above is true, will contain all addies /** whether to verify all email addresses (by regex) */ var $checkAddress = true; /*-----------------------------------------------------------------------------\ | public functions | \-----------------------------------------------------------------------------*/ /** * FUNCTION: autoCheck * * Sets auto checking to the value of $bool. * * @param bool $bool true/false * @access public */ function autoCheck ($bool) { $this->checkAddress = ($bool); } /** * FUNCTION: to * * Sets the To header for the message. * * @param string $toEmail email address * @param string $toName Name of recipient [optional] * @access public */ function to ($toEmail, $toName=null) { if (!$toEmail) return false; if ($this->checkAddress && !$this->validateEmail($toEmail)) vlibMimeMailError::raiseError('VM_ERROR_BADEMAIL', FATAL, 'To: '.$toEmail); if ($this->apply_windows_bugfix) array_push($this->all_emails, $toEmail); $this->sendto[] = ($toName == null) ? $toEmail : '"'.$toName.'" <'.$toEmail.'>'; } /** * FUNCTION: clearTo * * Clears all to headers set. * * @access public */ function clearTo () { $this->sendto = array(); $this->all_emails = array(); } /** * FUNCTION: cc * * Sets the Cc header for the message. * * @param string $ccEmail email address * @param string $ccName Name of recipient [optional] * @access public */ function cc ($ccEmail, $ccName=null) { if (!$ccEmail) return false; if ($this->checkAddress && !$this->validateEmail($ccEmail)) vlibMimeMailError::raiseError('VM_ERROR_BADEMAIL', FATAL, 'Cc: '.$ccEmail); if ($this->apply_windows_bugfix) array_push($this->all_emails, $ccEmail); $this->sendcc[] = ($ccName == null) ? $ccEmail : '"'.$ccName.'" <'.$ccEmail.'>'; } /** * FUNCTION: clearCc * * Clears all cc headers set. * * @access public */ function clearCc () { $this->sendcc = array(); $this->all_emails = array(); } /** * FUNCTION: bcc * * Sets the Bcc header for the message. * * @param string $bccEmail email address * @param string $bccName Name of recipient [optional] * @access public */ function bcc ($bccEmail, $bccName=null) { if (!$bccEmail) return false; if ($this->checkAddress && !$this->validateEmail($bccEmail)) vlibMimeMailError::raiseError('VM_ERROR_BADEMAIL', FATAL, 'Bcc: '.$bccEmail); if ($this->apply_windows_bugfix) array_push($this->all_emails, $bccEmail); $this->sendbcc[] = ($bccName == null) ? $bccEmail : '"'.$bccName.'" <'.$bccEmail.'>'; } /** * FUNCTION: clearBcc * * Clears all bcc headers set. * * @access public */ function clearBcc () { $this->sendbcc = array(); $this->all_emails = array(); } /** * FUNCTION: clearAll * * Clears all To, Bcc and Cc headers set. * * @access public */ function clearAll () { $this->clearTo(); $this->clearCc(); $this->clearBcc(); $this->all_emails = array(); } /** * FUNCTION: from * * Sets the From header for the message. * * @param string $fromEmail email address * @param string $fromName Name of recipient [optional] * @access public */ function from ($fromEmail, $fromName=null) { if (!$fromEmail) return false; if ($this->checkAddress && !$this->validateEmail($fromEmail)) vlibMimeMailError::raiseError('VM_ERROR_BADEMAIL', FATAL, 'From: '.$fromEmail); $this->xheaders['From'] = ($fromName == null) ? $fromEmail : '"'.$fromName.'" <'.$fromEmail.'>'; } /** * FUNCTION: replyTo * * Sets the ReplyTo header for the message. * * @param string $replytoEmail email address * @param string $replytoName Name of recipient [optional] * @access public */ function replyTo ($replytoEmail, $replytoName=null) { if (!$replytoEmail) return false; if ($this->checkAddress && !$this->validateEmail($replytoEmail)) vlibMimeMailError::raiseError('VM_ERROR_BADEMAIL', FATAL, 'Reply-To: '.$replytoEmail); $this->xheaders['Reply-To'] = ($replytoName == null) ? $replytoEmail : '"'.$replytoName.'" <'.$replytoEmail.'>'; } /** * FUNCTION: subject * * Sets the subject for this message. * * @param string $subject * @access public */ function subject ($subject) { $this->xheaders['Subject'] = strtr($subject, "\r\n", ' '); } /** * FUNCTION: body * * Sets the Body of the message. * If you're sending a mail with special characters, be sure to define the * charset. * i.e. $mail->body('ce message est en français.', 'iso-8859-1'); * * @param string $body plain text as the body * @param string $charset * @access public */ function body ($body, $charset='') { $this->body = $body; if($charset != '') { $this->charset = strtolower($charset); if($this->charset != 'us-ascii') $this->ctencoding = '8bit'; } } /** * FUNCTION: htmlBody * * Sets the HTML Body of the message. * You can you the body() function or htmlBody() or both just to be certain that * the user will be able to see the stuff you're sending. * * If you're sending a mail with special characters, be sure to define the * charset. * i.e. $mail->htmlbody('ce message est en français.', 'iso-8859-1'); * * @param string $htmlbody html text as the body * @param string $charset * @access public */ function htmlBody ($htmlbody, $charset='') { $this->htmlbody = $htmlbody; if($charset != '') { $this->htmlcharset = strtolower($charset); if($this->htmlcharset != 'us-ascii') $this->htmlctencoding = '8bit'; } } /** * FUNCTION: attach * * Attach a file to the message. Defaults the disposition to 'attachment', * you can also use 'inline' which the client will try to show in the message. * Mime-types can be handled by vlibMimeMail by the list found in * vlibCommon/mime_types.php. * * @param string $filename full path of the file to attach * @param string $disposition inline or attachment * @param string $mimetype MIME-type of the file. defaults to 'application/octet-stream' * @access public */ function attach ($filename, $disposition = 'attachment', $mimetype=null, $cid=null) { if($mimetype == null) $mimetype = vlibCommon::getMimeType($filename); $this->attachments[] = $filename; $this->mimetypes[] = $mimetype; $this->dispositions[] = $disposition; if (!$cid) { srand((double)microtime()*96545624); $cid = md5(uniqid(rand())).'@vlib.mimemail'; } $this->contentIDs[] = $cid; return $cid; } /** * FUNCTION: organization * * Sets the Organization header for the message. * * @param string $org organization name * @access public */ function organization ($org) { if(!empty($org)) $this->xheaders['Organization'] = $org; } /** * FUNCTION: receipt * * To request a receipt you must call this function with a true value. * And you must call $this->from() or $this->replyTo() before sending the mail. * * @param bool $bool true/false * @access public */ function receipt ($bool=true) { $this->receipt = ($bool); } /** * FUNCTION: priority * * Sets the Priority header for the message. * usage: $mail->priority(1); // highest setting * view documentation for priority levels. * * @param string $priority * @access public */ function priority ($priority) { if(!is_int($priority)) $priority = settype($priority, 'integer'); if(!isset($this->priorities[$priority-1])) return false; $this->xheaders['X-Priority'] = $this->priorities[$priority-1]; return true; } /** * FUNCTION: validateEmail * * Validates an email address and return true or false. * * @param string $address email address * @return bool true/false * @access public */ function validateEmail ($address) { return preg_match('/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9_-]+(\.[_a-z0-9-]+)+$/i',$address); } /** * FUNCTION: send * * Sends the mail. * * @return boolean true on success, false on failure * @access public */ function send () { $this->_buildMail(); $to_str = ($this->apply_windows_bugfix) ? implode(',', $this->all_emails) : $this->xheaders['To']; return mail($to_str, $this->xheaders['Subject'], $this->fullBody, $this->headers); } /** * FUNCTION: get * * Returns the whole e-mail, headers and message. Can be used to display the * message in pain text or for debugging. * * @return string message * @access public */ function get () { $this->_buildMail(); $mail = 'To: '.$this->xheaders['To']."\n"; $mail .= 'Subject: '.$this->xheaders['Subject']."\n"; $mail .= $this->headers . "\n"; $mail .= $this->fullBody; return $mail; } /*-----------------------------------------------------------------------------\ | private functions | \-----------------------------------------------------------------------------*/ /** * FUNCTION: vlibMimeMail [contsructor] * * Enables auto checking by default. * Also creates the unique boundary id for this message. * * @param bool $apply_windows_bugfix tells us whether to apply bug fix for windows Cc: and Bcc: headers. * @access private */ function vlibMimeMail ($apply_windows_bugfix=false) { $this->apply_windows_bugfix = ($apply_windows_bugfix); $this->boundary = "--" . md5(uniqid('vlibseediganoofahilfaman')); $this->boundary_alt = "--" . md5(uniqid('vlibseedvatefairechier')); } /** * FUNCTION: _buildMail * * Proccesses all headers and attachments ready for sending. * * @access private */ function _buildMail () { if (empty($this->sendto) && (empty($this->body) && empty($this->htmlbody))) { vlibMimeMailError::raiseError('VM_ERROR_CANNOT_SEND', FATAL); } // build the headers $this->headers = ""; $this->xheaders['To'] = implode(',', $this->sendto); $cc_header_name = ($this->apply_windows_bugfix) ? 'cc': 'Cc'; if (!empty($this->sendcc)) $this->xheaders[$cc_header_name] = implode(',', $this->sendcc); if (!empty($this->sendbcc)) $this->xheaders['Bcc'] = implode(',', $this->sendbcc); if($this->receipt) { if(isset($this->xheaders['Reply-To'])) { $this->xheaders['Disposition-Notification-To'] = $this->xheaders['Reply-To']; } elseif (isset($this->xheaders['From'])) { $this->xheaders['Disposition-Notification-To'] = $this->xheaders['From']; } } if($this->charset != '') { $this->xheaders['Mime-Version'] = '1.0'; $this->xheaders['Content-Type'] = 'text/plain; charset='.$this->charset; $this->xheaders['Content-Transfer-Encoding'] = $this->ctencoding; } $this->xheaders['X-Mailer'] = 'vlibMimeMail'; // setup the body ready for sending $this->_setBody(); foreach ($this->xheaders as $head => $value) { $rgx = ($this->apply_windows_bugfix) ? 'Subject' : 'Subject|To'; // don't strip out To header for bugfix if (!preg_match('/^'.$rgx.'$/i', $head)) $this->headers .= $head.': '.strtr($value, "\r\n", ' ')."\n"; } } /** * FUNCTION: _setBody * * sets the body to be used in a mail. * * @access private */ function _setBody () { // do we need to encode?? $encode = (empty($this->htmlbody) && empty($this->attachments)) ? false : true; // if yes... if ($encode) { $this->fullBody = "This is a multi-part message in MIME format.\n\n"; $this->fullBody .= '--'.$this->boundary."\nContent-Type: multipart/alternative;\n\tboundary=\"".$this->boundary_alt."\"\n\n\n"; $body_boundary = $this->boundary_alt; $this->xheaders['Content-Type'] = "multipart/mixed;\n\tboundary=\"".$this->boundary.'"'; if (!empty($this->body)) { $this->fullBody .= '--'.$body_boundary."\nContent-Type: text/plain; charset=".$this->charset."\nContent-Transfer-Encoding: ".$this->ctencoding."\n\n".$this->body."\n\n"; } if (!empty($this->htmlbody)) { $this->fullBody .= '--'.$body_boundary."\nContent-Type: text/html; charset=".$this->charset."\nContent-Transfer-Encoding: ".$this->ctencoding."\n\n".$this->htmlbody."\n\n"; } $this->fullBody .= '--'.$body_boundary."--\n\n"; if (!empty($this->attachments)) { $this->_build_attachments(); } $this->fullBody .= '--'.$this->boundary.'--'; // ends the last boundary } // else we just send plain text. else { if (!empty($this->body)) { $this->fullBody = $this->body; } else { vlibMimeMailError::raiseError('VM_ERROR_NOBODY', FATAL); } } } /** * FUNCTION: _build_attachments * * Checks and encodes all attachments. * * @access private */ function _build_attachments () { $sep = chr(13).chr(10); $ata = array(); $k=0; for ($i=0; $i < count( $this->attachments); $i++) { $filename = $this->attachments[$i]; $basename = basename($filename); $mimetype = $this->mimetypes[$i]; $disposition = $this->dispositions[$i]; $contentID = $this->contentIDs[$i]; if (preg_match('/^[a-zA-Z]+:\/\//', $filename)) { // figure out if local or remote $upart = parse_url($filename); $newfilename = $upart['scheme'].'://'; if (!empty($upart['user'])) $newfilename .= $upart['user'].':'.$upart['pass'].'@'; $newfilename .= $upart['host']; if (!empty($upart['port'])) $newfilename .= ':'.$upart['port']; $newfilename .= '/'; if (!empty($upart['path'])) { $upart['path'] = substr($upart['path'], 1); $newpath = explode('/', $upart['path']); for($i=0; $iboundary."\nContent-type: ".$mimetype.";\n\tname=\"".$basename."\"\nContent-Transfer-Encoding: base64\nContent-Disposition: ".$disposition.";\n\tfilename=\"".$basename."\"\n"; if ($contentID) $subhdr .= 'Content-ID: <'.$contentID.">\n"; $ata[$k++] = $subhdr; $ata[$k++] = chunk_split(base64_encode($data))."\n\n"; fclose($fp); } $this->fullBody .= "\n".implode($sep, $ata); } } // class vlibMimeMail } // << end if(!defined()).. ?>