root/trunk/trax/vendor/trax/action_mailer.php

Revision 327, 16.4 KB (checked in by john, 2 years ago)

AR changed the count on paginated queries, added session_cookie_domain to the Trax class

  • Property svn:keywords set to Id
Line 
1<?php
2/**
3 *  File for ActionMailer class
4 *
5 *  (PHP 5)
6 *
7 *  @package PHPonTrax
8 *  @version $Id$
9 *  @copyright (c) 2005 John Peterson
10 *
11 *  Permission is hereby granted, free of charge, to any person obtaining
12 *  a copy of this software and associated documentation files (the
13 *  "Software"), to deal in the Software without restriction, including
14 *  without limitation the rights to use, copy, modify, merge, publish,
15 *  distribute, sublicense, and/or sell copies of the Software, and to
16 *  permit persons to whom the Software is furnished to do so, subject to
17 *  the following conditions:
18 *
19 *  The above copyright notice and this permission notice shall be
20 *  included in all copies or substantial portions of the Software.
21 *
22 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/**
32 *
33 */
34include_once( "Mail.php" );
35include_once( "Mail/mime.php" );
36
37/**
38 *
39 *  @package PHPonTrax
40 */
41class ActionMailer {
42
43    private
44        $mail_mime = null,  # Mail_mime object
45        $mail = null, # Mail object to deliver mail
46        $mime_params = array(), # params for charset
47        $errors = array(); # array to hold any errors
48    public
49        $smtp_settings = array( 
50            'host'      => 'localhost', # The server to connect.
51            'port'      => 25,  # The port to connect.
52            'persist'   => false, # Indicates whether or not the SMTP connection should persist over multiple sends.
53            'auth'      => false, # Whether or not to use SMTP authentication.
54            'username'  => null, # The username to use for SMTP authentication.
55            'password'  => null, # The password to use for SMTP authentication.           
56        ),
57        $sendmail_settings = array(
58            'path' => '/usr/sbin/sendmail',
59            'args' => '-i -t'
60        ),
61        $delivery_method = "mail", # mail | sendmail | smtp | test
62        $perform_deliveries = true, # true will attempt to deliver mail | false will not deliver mail
63        $default_charset = "utf-8", # default charset for email.
64        $head_charset = null, # charset for email headers.
65        $html_charset = null, # charset for html email body.
66        $text_charset = null, # charset for text email body.
67        $template = null, # view file to use for body of email.
68        $template_root = null, # template_root determines the base from which template references will be made.
69        $deliveries = array(), # if delivery_method is "test" it will not deliver but store emails in this array.
70        $recipients = null, # to address(es)
71        $subject = null, # email subject
72        $from = null, # from email address
73        $default_from = null, # if no from specified use this as the from.
74        $body = array(), # array set in child class of values for view template.
75        $preparse_body = array(), # holder for orginal body array from child class
76        $headers = array(), # email headers
77        $crlf = "\r\n", # linefeed char
78        $content_type = "text"; # text | html | both
79
80    /**
81     *  ActionMailer constructor.
82     *  @todo Document this API
83     */ 
84    function __construct() {
85        $this->mail_mime = new Mail_mime($this->crlf);               
86    }
87
88    /**
89     *  Override call() to do some magic where you can call create_*() and deliver_*().
90     *  @todo Document this API
91     */     
92    function __call($method_name, $parameters) {
93        if(method_exists($this, $method_name)) {
94            # If the method exists, just call it
95            $result = call_user_func_array(array($this,$method_name), $parameters);
96        } else {
97            if(preg_match("/^create_([_a-z]\w*)/", $method_name, $matches)) {
98                $result = $this->create_mail($matches[1], $parameters);
99            } elseif(preg_match("/^deliver_([_a-z]\w*)/", $method_name, $matches)) {             
100                $result = $this->create_mail($matches[1], $parameters);
101                if(!$this->deliver($result)) {
102                    $result = false;   
103                }
104            }
105        }
106        return $result;
107    }
108
109    /**
110     *  Set all the necessary email headers
111     *  @todo Document this API
112     */     
113    private function set_headers() {
114        if(!is_null($this->recipients)) {
115            $recipients = $this->format_emails($this->recipients, "To");
116            $this->set_header_line("To", $recipients); 
117        }
118       
119        if(!is_null($this->cc)) {
120            $cc = $this->format_emails($this->cc, "Cc");
121            $this->set_header_line("Cc", $cc);           
122        }
123
124        if(!is_null($this->bcc)) {
125            $bcc = $this->format_emails($this->bcc, "Bcc");
126            $this->set_header_line("Bcc", $bcc);           
127        }
128
129        if(!is_null($this->reply_to)) {
130            $reply_to = $this->format_emails($this->reply_to, "Reply-To");
131            $this->set_header_line("Reply-To", $reply_to);           
132        }
133       
134        if(is_null($this->from) || $this->from == '') {
135            $this->from = $this->default_from;           
136        } 
137        $from = $this->format_emails($this->from, "From");
138        $this->set_header_line("From", $from);
139       
140        if(!is_null($this->subject))  {
141            $this->set_header_line("Subject", ereg_replace("[\n\r]", "", $this->subject));
142        } else {
143            $this->set_header_line("Subject", "");
144        }
145
146        if(!array_key_exists("Date", $this->headers)) {
147            $this->set_header_line("Date", date("r"));
148        }
149       
150        if(!array_key_exists("Return-Path", $this->headers) && !is_null($this->from_address)) {
151            $this->set_header_line("Return-Path", $this->from_address);
152        } 
153         
154        if(!array_key_exists("Reply-To", $this->headers) && !is_null($this->from_address)) {
155            $this->set_header_line("Reply-To", $this->from_address);           
156        }
157    }
158
159    /**
160     *  Format an array of emails into a correct string / validate emails.
161     *  @todo Document this API
162     */   
163    private function format_emails($emails, $type = null) {
164     
165        $email_addresses = null;     
166        if(!is_null($emails) && is_string($emails)) {
167            if(strstr($emails, ",")) {
168                $emails = explode(",", $emails);       
169            } else {
170                $emails = array($emails);   
171            }   
172        }       
173        if(is_array($emails)) {
174            foreach($emails as $email) {
175                if($this->validate_email($email)) {
176                    $email_addresses[] = $email;
177                } else {
178                    if($type) {
179                        $type = "$type ";   
180                    }
181                    $this->errors[] = "Invalid ".$type."email address: ".$email;   
182                }
183            }
184            if(is_array($email_addresses)) {
185                $email_addresses = implode(",", $email_addresses);
186            }                     
187        }     
188
189        return $email_addresses;           
190    }
191
192    /**
193     *  Set the text body of the email.
194     *  @todo Document this API
195     */   
196    private function set_text_body($text) {
197        if(strlen($text) > 0) {
198            $this->mail_mime->setTxtBody($text);
199        }
200    }
201
202    /**
203     *  Set the html body of the email.
204     *  @todo Document this API
205     */
206    private function set_html_body($html) {
207        if(strlen($html) > 0) {
208            $this->mail_mime->setHTMLBody($html);
209        }
210    }   
211
212    /**
213     *  Sets up default class variables for this mailer.  Classes extending
214     *  ActionMailer can override these values.
215     *  @todo Document this API
216     */
217    private function initialize_defaults($method_name) {       
218        $this->template_root = Trax::$views_path;
219        $this->template_path = "{$this->template_root}/".Inflector::underscore(get_class($this));
220        $this->template = $this->template ? $this->template : $method_name;       
221        #$this->headers = $this->headers ? $this->headers : array();
222        $this->headers = array();
223        #$this->body = $this->body ? $this->body : array();   
224        $this->body = null;
225        $this->default_from = "nobody@".($_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : 'domain.com');
226        $this->head_charset = $this->head_charset ? $this->head_charset : $this->default_charset;
227        $this->html_charset = $this->html_charset ? $this->html_charset : $this->default_charset;
228        $this->text_charset = $this->text_charset ? $this->text_charset : $this->default_charset;       
229    }
230
231    /**
232     *  Sets up and creates the email for deliver().
233     *  @todo Document this API
234     */
235    private function create_mail($method_name, $parameters = array()) { 
236        $this->initialize_defaults($method_name);
237        if(method_exists($this, $method_name)) {
238            //echo "calling $method_name<br>";
239            call_user_func_array(array($this, $method_name), $parameters);   
240        } 
241        $this->mime_params = array(
242            'head_charset' => $this->head_charset, 
243            'html_charset' =>  $this->html_charset,
244            'text_charset' =>  $this->text_charset
245        );           
246        $this->set_headers();
247        $body = $this->preparse_body = $this->body;
248        if(!is_string($body)) {
249            $body = $this->render_message($method_name, $body);
250        }
251        if($this->content_type == "html") {
252            $this->set_html_body($body);       
253        } elseif($this->content_type == "both") {
254            $this->set_html_body($body); 
255            $this->set_text_body($body);   
256        } else {
257            $this->set_text_body($body);       
258        }
259           
260        $this->body = $this->mail_mime->get($this->mime_params);     
261        $this->headers = $this->mail_mime->headers($this->headers, true); 
262
263        if($this->delivery_method == "sendmail") {
264            $this->mail =& Mail::factory("sendmail", $this->sendmail_settings);
265        } elseif($this->delivery_method == "smtp") {
266            $this->mail =& Mail::factory("smtp", $this->smtp_settings);
267        } else {
268            $this->mail =& Mail::factory("mail");   
269        }
270
271        return $this;
272    }
273
274    /**
275     *  Load the template view file for the body of the email.
276     *  @todo Document this API
277     */
278    function render_message($method_name, $body = array()) {
279        if(strstr($method_name, "/")) {
280            $template = "{$this->template_root}/{$method_name}.".Trax::$views_extension;
281        } else {
282            $template = "{$this->template_path}/{$method_name}.".Trax::$views_extension;
283        }
284
285        if(file_exists($template)) {
286            # start to buffer output
287            ob_start(); 
288            if(count($body)) {
289                extract($body); 
290            }
291            include($template);
292            $result = ob_get_contents();
293            ob_end_clean();
294        }
295        return $result;       
296    }
297
298    /**
299     *  Uses ActionControllers render_partial method.
300     *  @todo Document this API
301     */     
302    function render_partial($path, $options = array()) {
303        $locals = $this->preparse_body;
304        if(is_array($options['locals']) && is_array($locals)) {
305            $options['locals'] = array_merge($locals, $options['locals']);
306        } elseif(is_array($locals)) {
307            $options['locals'] = $locals;   
308        }
309        $ar = new ActionController();
310        $ar->views_path = $this->template_path;
311        $ar->render_partial($path, $options);                     
312    }
313
314    /**
315     *  Return a text version of the email currently loaded.
316     *  @todo Document this API
317     */   
318    function encoded($add_pre_tags = false) {                   
319        if(!count($this->errors)) {
320            list(, $text_headers) = $this->mail->prepareHeaders($this->headers);
321            $email = $text_headers.$this->crlf.$this->crlf.$this->body;
322            if($add_pre_tags) {
323                $email = "<pre>".$email."</pre>";   
324            }
325        } else {
326            $email = $this->get_errors_as_string("\n");   
327        }
328        return $email;
329    }
330
331    /**
332     *  Sends the email loaded into this object via create_mail().
333     *  @todo Document this API
334     */   
335    function deliver($mail = null) {
336        if(is_null($mail)) { 
337            $mail =& $this;               
338        } 
339        if($this->perform_deliveries) {
340            if($this->delivery_method == "test") {
341                $this->deliveries[] = $mail->encoded();
342                return true;   
343            }
344            if(!count($this->errors)) { 
345                #error_log("delivering message to:".$mail->headers['To']);
346                $result = $mail->mail->send($mail->headers['To'], $mail->headers, $mail->body);
347                if(is_object($result)) { 
348                    $this->errors[] = $result->getMessage();
349                    return false;
350                } 
351            } else {
352                return false;
353            }
354        }
355        return true;
356    }
357
358    /**
359     *  Add an attachment to an email.
360     *  @todo Document this API
361     */
362    function add_attachment($file, $content_type ='application/octet-stream', $file_name = '', $is_file = true, $encoding = 'base64') {
363        $this->mail_mime->addAttachment($file, $content_type, $file_name, $is_file, $encoding);
364    }
365
366    /**
367     *  Validates a single email address
368     *
369     *  @param string $email
370     *    Validates the input $email is in format:
371     *      user@domain.com or "John Smith <user@domain.com>"
372     *  @return boolean
373     *    <ul>
374     *      <li>true => Valid email, no errors found.
375     *      <li>false => Email not valid</li>
376     *    </ul>
377     */
378    function validate_email($email) {
379        if(eregi("^[a-zA-Z0-9._-]+@([a-zA-Z0-9._-]+\.)+([a-zA-Z0-9_-]){2,4}$", $email) ||
380           eregi("^([ '_a-zA-Z0-9]\w*)+<[a-zA-Z0-9._-]+@([a-zA-Z0-9._-]+\.)+([a-zA-Z0-9_-]){2,4}>$", $email)) {
381            return true;
382        }
383        return false;
384    }
385
386    /**
387     *  Set a single line for the header of an email
388     *
389     *  @uses $headers
390     *  @param string $header_key
391     *    key for the header line (To:, From:, Subject:, etc)
392     *  @param string $header_value
393     *    value for the $header_key
394     */
395    function set_header_line($header_key, $header_value) {
396        if($header_key && $header_value) {
397            $this->headers[$header_key] = $header_value;
398        }
399    }
400   
401    /**
402     *  Add or overwrite description of an error to the list of errors
403     *  @param string $error Error message text
404     *  @param string $key Key to associate with the error (in the
405     *    simple case, column name).  If omitted, numeric keys will be
406     *    assigned starting with 0.  If specified and the key already
407     *    exists in $errors, the old error message will be overwritten
408     *    with the value of $error.
409     *  @uses $errors
410     */
411    function add_error($error, $key = null) {
412        if(!is_null($key)) { 
413            $this->errors[$key] = $error;
414        } else {
415            $this->errors[] = $error;
416        }
417    }
418   
419    /**
420     *  Return description of non-fatal errors
421     *
422     *  @uses $errors
423     *  @param boolean $return_string
424     *    <ul>
425     *      <li>true => Concatenate all error descriptions into a string
426     *        using $seperator between elements and return the
427     *        string</li>
428     *      <li>false => Return the error descriptions as an array</li>
429     *    </ul>
430     *  @param string $seperator  String to concatenate between error
431     *    descriptions if $return_string == true
432     *  @return mixed Error description(s), if any
433     */
434    function get_errors($return_string = false, $seperator = "<br>") {
435        if($return_string && count($this->errors) > 0) {
436            return implode($seperator, $this->errors);
437        } else {
438            return $this->errors;
439        }
440    }
441
442    /**
443     *  Return errors as a string.
444     *
445     *  Concatenate all error descriptions into a stringusing
446     *  $seperator between elements and return the string.
447     *  @param string $seperator  String to concatenate between error
448     *    descriptions
449     *  @return string Concatenated error description(s), if any
450     */
451    function get_errors_as_string($seperator = "<br>") {
452        return $this->get_errors(true, $seperator);
453    }
454
455}
456
457
458?>
Note: See TracBrowser for help on using the browser.