Location: PHPKode > projects > PHP on Trax > vendor/trax/action_mailer.php
<?php
/**
 *  File for ActionMailer class
 *
 *  (PHP 5)
 *
 *  @package PHPonTrax
 *  @version $Id: action_mailer.php 327 2009-09-26 15:40:51Z john $
 *  @copyright (c) 2005 John Peterson
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 *
 */
include_once( "Mail.php" );
include_once( "Mail/mime.php" );

/**
 *
 *  @package PHPonTrax
 */
class ActionMailer {

    private
        $mail_mime = null,  # Mail_mime object
        $mail = null, # Mail object to deliver mail
        $mime_params = array(), # params for charset
        $errors = array(); # array to hold any errors
    public
        $smtp_settings = array( 
            'host'      => 'localhost', # The server to connect.
            'port'      => 25,  # The port to connect.
            'persist'   => false, # Indicates whether or not the SMTP connection should persist over multiple sends.
            'auth'      => false, # Whether or not to use SMTP authentication.
            'username'  => null, # The username to use for SMTP authentication.
            'password'  => null, # The password to use for SMTP authentication.            
        ),
        $sendmail_settings = array(
            'path' => '/usr/sbin/sendmail',
            'args' => '-i -t'
        ),
        $delivery_method = "mail", # mail | sendmail | smtp | test
        $perform_deliveries = true, # true will attempt to deliver mail | false will not deliver mail
        $default_charset = "utf-8", # default charset for email.
        $head_charset = null, # charset for email headers.
        $html_charset = null, # charset for html email body.
        $text_charset = null, # charset for text email body.
        $template = null, # view file to use for body of email.
        $template_root = null, # template_root determines the base from which template references will be made.
        $deliveries = array(), # if delivery_method is "test" it will not deliver but store emails in this array.
        $recipients = null, # to address(es)
        $subject = null, # email subject
        $from = null, # from email address
        $default_from = null, # if no from specified use this as the from.
        $body = array(), # array set in child class of values for view template.
        $preparse_body = array(), # holder for orginal body array from child class
        $headers = array(), # email headers
        $crlf = "\r\n", # linefeed char
        $content_type = "text"; # text | html | both

    /**
     *  ActionMailer constructor.
     *  @todo Document this API
     */ 
    function __construct() {
        $this->mail_mime = new Mail_mime($this->crlf);               
    }

    /**
     *  Override call() to do some magic where you can call create_*() and deliver_*().
     *  @todo Document this API
     */     
    function __call($method_name, $parameters) {
        if(method_exists($this, $method_name)) {
            # If the method exists, just call it
            $result = call_user_func_array(array($this,$method_name), $parameters);
        } else {
            if(preg_match("/^create_([_a-z]\w*)/", $method_name, $matches)) {
                $result = $this->create_mail($matches[1], $parameters);
            } elseif(preg_match("/^deliver_([_a-z]\w*)/", $method_name, $matches)) {              
                $result = $this->create_mail($matches[1], $parameters);
                if(!$this->deliver($result)) {
                    $result = false;    
                }
            }
        }
        return $result;
    }

    /**
     *  Set all the necessary email headers
     *  @todo Document this API
     */     
    private function set_headers() {
        if(!is_null($this->recipients)) {
            $recipients = $this->format_emails($this->recipients, "To");
            $this->set_header_line("To", $recipients); 
        }
        
        if(!is_null($this->cc)) {
            $cc = $this->format_emails($this->cc, "Cc");
            $this->set_header_line("Cc", $cc);            
        }

        if(!is_null($this->bcc)) {
            $bcc = $this->format_emails($this->bcc, "Bcc");
            $this->set_header_line("Bcc", $bcc);            
        }

        if(!is_null($this->reply_to)) {
            $reply_to = $this->format_emails($this->reply_to, "Reply-To");
            $this->set_header_line("Reply-To", $reply_to);            
        }
        
        if(is_null($this->from) || $this->from == '') {
            $this->from = $this->default_from;            
        } 
        $from = $this->format_emails($this->from, "From");
        $this->set_header_line("From", $from);
        
        if(!is_null($this->subject))  {
            $this->set_header_line("Subject", ereg_replace("[\n\r]", "", $this->subject));
        } else {
            $this->set_header_line("Subject", "");
        }

        if(!array_key_exists("Date", $this->headers)) {
            $this->set_header_line("Date", date("r"));
        }
        
        if(!array_key_exists("Return-Path", $this->headers) && !is_null($this->from_address)) {
            $this->set_header_line("Return-Path", $this->from_address);
        }  
          
        if(!array_key_exists("Reply-To", $this->headers) && !is_null($this->from_address)) {
            $this->set_header_line("Reply-To", $this->from_address);            
        }
    }

    /**
     *  Format an array of emails into a correct string / validate emails.
     *  @todo Document this API
     */    
    private function format_emails($emails, $type = null) {
     
        $email_addresses = null;     
        if(!is_null($emails) && is_string($emails)) {
            if(strstr($emails, ",")) {
                $emails = explode(",", $emails);        
            } else {
                $emails = array($emails);    
            }    
        }        
        if(is_array($emails)) {
            foreach($emails as $email) {
                if($this->validate_email($email)) {
                    $email_addresses[] = $email;
                } else {
                    if($type) {
                        $type = "$type ";    
                    }
                    $this->errors[] = "Invalid ".$type."email address: ".$email;    
                }
            }
            if(is_array($email_addresses)) {
                $email_addresses = implode(",", $email_addresses);
            }                     
        }      

        return $email_addresses;           
    }

    /**
     *  Set the text body of the email.
     *  @todo Document this API
     */    
    private function set_text_body($text) {
        if(strlen($text) > 0) {
            $this->mail_mime->setTxtBody($text);
        }
    }

    /**
     *  Set the html body of the email.
     *  @todo Document this API
     */
    private function set_html_body($html) {
        if(strlen($html) > 0) {
            $this->mail_mime->setHTMLBody($html);
        }
    }    

    /**
     *  Sets up default class variables for this mailer.  Classes extending
     *  ActionMailer can override these values.
     *  @todo Document this API
     */
    private function initialize_defaults($method_name) {       
        $this->template_root = Trax::$views_path;
        $this->template_path = "{$this->template_root}/".Inflector::underscore(get_class($this));
        $this->template = $this->template ? $this->template : $method_name;        
        #$this->headers = $this->headers ? $this->headers : array();
		$this->headers = array();
        #$this->body = $this->body ? $this->body : array();    
		$this->body = null;
        $this->default_from = "nobody@".($_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : 'domain.com');
        $this->head_charset = $this->head_charset ? $this->head_charset : $this->default_charset;
        $this->html_charset = $this->html_charset ? $this->html_charset : $this->default_charset;
        $this->text_charset = $this->text_charset ? $this->text_charset : $this->default_charset;        
    }

    /**
     *  Sets up and creates the email for deliver().
     *  @todo Document this API
     */
    private function create_mail($method_name, $parameters = array()) {  
        $this->initialize_defaults($method_name);
        if(method_exists($this, $method_name)) {
            //echo "calling $method_name<br>";
            call_user_func_array(array($this, $method_name), $parameters);   
        } 
        $this->mime_params = array(
            'head_charset' => $this->head_charset, 
            'html_charset' =>  $this->html_charset,
            'text_charset' =>  $this->text_charset
        );            
        $this->set_headers();
        $body = $this->preparse_body = $this->body;
        if(!is_string($body)) {
            $body = $this->render_message($method_name, $body);
        }
        if($this->content_type == "html") {
            $this->set_html_body($body);       
        } elseif($this->content_type == "both") {
            $this->set_html_body($body); 
            $this->set_text_body($body);   
        } else {
            $this->set_text_body($body);        
        }
           
        $this->body = $this->mail_mime->get($this->mime_params);      
        $this->headers = $this->mail_mime->headers($this->headers, true);  

        if($this->delivery_method == "sendmail") {
            $this->mail =& Mail::factory("sendmail", $this->sendmail_settings);
        } elseif($this->delivery_method == "smtp") {
            $this->mail =& Mail::factory("smtp", $this->smtp_settings);
        } else {
            $this->mail =& Mail::factory("mail");    
        }

        return $this;
    }

    /**
     *  Load the template view file for the body of the email.
     *  @todo Document this API
     */
    function render_message($method_name, $body = array()) {
        if(strstr($method_name, "/")) {
            $template = "{$this->template_root}/{$method_name}.".Trax::$views_extension;
        } else {
            $template = "{$this->template_path}/{$method_name}.".Trax::$views_extension;
        }

        if(file_exists($template)) {
            # start to buffer output
            ob_start(); 
            if(count($body)) {
                extract($body);  
            }
            include($template);
            $result = ob_get_contents();
            ob_end_clean();
        }
        return $result;        
    }

    /**
     *  Uses ActionControllers render_partial method.
     *  @todo Document this API
     */      
    function render_partial($path, $options = array()) {
        $locals = $this->preparse_body;
        if(is_array($options['locals']) && is_array($locals)) {
            $options['locals'] = array_merge($locals, $options['locals']);
        } elseif(is_array($locals)) {
            $options['locals'] = $locals;    
        }
        $ar = new ActionController();
        $ar->views_path = $this->template_path;
        $ar->render_partial($path, $options);                     
    }

    /**
     *  Return a text version of the email currently loaded.
     *  @todo Document this API
     */    
    function encoded($add_pre_tags = false) {                   
        if(!count($this->errors)) {
            list(, $text_headers) = $this->mail->prepareHeaders($this->headers);
            $email = $text_headers.$this->crlf.$this->crlf.$this->body;
            if($add_pre_tags) {
                $email = "<pre>".$email."</pre>";    
            }
        } else {
            $email = $this->get_errors_as_string("\n");    
        }
        return $email;
    }

    /**
     *  Sends the email loaded into this object via create_mail().
     *  @todo Document this API
     */    
    function deliver($mail = null) {
        if(is_null($mail)) {  
            $mail =& $this;               
        } 
        if($this->perform_deliveries) {
            if($this->delivery_method == "test") {
                $this->deliveries[] = $mail->encoded();
                return true;    
            }
            if(!count($this->errors)) {  
				#error_log("delivering message to:".$mail->headers['To']);
                $result = $mail->mail->send($mail->headers['To'], $mail->headers, $mail->body);
                if(is_object($result)) { 
                    $this->errors[] = $result->getMessage();
                    return false;
                } 
            } else {
                return false;
            }
        }
        return true;
    }

    /**
     *  Add an attachment to an email.
     *  @todo Document this API
     */
    function add_attachment($file, $content_type ='application/octet-stream', $file_name = '', $is_file = true, $encoding = 'base64') {
        $this->mail_mime->addAttachment($file, $content_type, $file_name, $is_file, $encoding);
    }

    /**
     *  Validates a single email address
     *
     *  @param string $email
     *    Validates the input $email is in format:
     *      hide@address.com or "John Smith <hide@address.com>"
     *  @return boolean 
     *    <ul>
     *      <li>true => Valid email, no errors found.
     *      <li>false => Email not valid</li>
     *    </ul>
     */
    function validate_email($email) {
        if(eregi("^[a-zA-Z0-9._-]+@([a-zA-Z0-9._-]+\.)+([a-zA-Z0-9_-]){2,4}$", $email) ||
           eregi("^([ '_a-zA-Z0-9]\w*)+<[a-zA-Z0-9._-]+@([a-zA-Z0-9._-]+\.)+([a-zA-Z0-9_-]){2,4}>$", $email)) {
            return true;
        }
        return false;
    }

    /**
     *  Set a single line for the header of an email
     *
     *  @uses $headers
     *  @param string $header_key
     *    key for the header line (To:, From:, Subject:, etc)
     *  @param string $header_value
     *    value for the $header_key 
     */
    function set_header_line($header_key, $header_value) {
        if($header_key && $header_value) {
            $this->headers[$header_key] = $header_value;
        }
    }
    
    /**
     *  Add or overwrite description of an error to the list of errors
     *  @param string $error Error message text
     *  @param string $key Key to associate with the error (in the
     *    simple case, column name).  If omitted, numeric keys will be
     *    assigned starting with 0.  If specified and the key already
     *    exists in $errors, the old error message will be overwritten
     *    with the value of $error.
     *  @uses $errors
     */
    function add_error($error, $key = null) {
        if(!is_null($key)) { 
            $this->errors[$key] = $error;
        } else {
            $this->errors[] = $error;
        }
    }
    
    /**
     *  Return description of non-fatal errors
     *
     *  @uses $errors
     *  @param boolean $return_string
     *    <ul>
     *      <li>true => Concatenate all error descriptions into a string
     *        using $seperator between elements and return the
     *        string</li>
     *      <li>false => Return the error descriptions as an array</li>
     *    </ul>
     *  @param string $seperator  String to concatenate between error
     *    descriptions if $return_string == true
     *  @return mixed Error description(s), if any
     */
    function get_errors($return_string = false, $seperator = "<br>") {
        if($return_string && count($this->errors) > 0) {
            return implode($seperator, $this->errors);
        } else {
            return $this->errors;
        }
    }

    /**
     *  Return errors as a string.
     *
     *  Concatenate all error descriptions into a stringusing
     *  $seperator between elements and return the string.
     *  @param string $seperator  String to concatenate between error
     *    descriptions
     *  @return string Concatenated error description(s), if any
     */
    function get_errors_as_string($seperator = "<br>") {
        return $this->get_errors(true, $seperator);
    }

}


?>
Return current item: PHP on Trax