1: <?php
2: /**
3: * Internal PHP-mail() interface.
4: *
5: * LICENSE:
6: *
7: * Copyright (c) 2010 Chuck Hagenbuch
8: * All rights reserved.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: *
14: * o Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * o Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * o The names of the authors may not be used to endorse or promote
20: * products derived from this software without specific prior written
21: * permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34: *
35: * @category Horde
36: * @package Mail
37: * @author Chuck Hagenbuch <chuck@horde.org>
38: * @author Michael Slusarz <slusarz@horde.org>
39: * @copyright 2010 Chuck Hagenbuch
40: * @copyright 2010 Michael Slusarz
41: * @license http://www.horde.org/licenses/bsd New BSD License
42: */
43:
44: /**
45: * Internal PHP-mail() interface.
46: *
47: * @category Horde
48: * @package Mail
49: */
50: class Horde_Mail_Transport_Mail extends Horde_Mail_Transport
51: {
52: /**
53: * Constructor.
54: *
55: * @param array $params Additional parameters:
56: * - args: (string) Extra arguments for the mail() function.
57: */
58: public function __construct(array $params = array())
59: {
60: $this->_params = array_merge($this->_params, $params);
61: }
62:
63: /**
64: * Send a message.
65: *
66: * @param mixed $recipients Either a comma-seperated list of recipients
67: * (RFC822 compliant), or an array of
68: * recipients, each RFC822 valid. This may
69: * contain recipients not specified in the
70: * headers, for Bcc:, resending messages, etc.
71: * @param array $headers The headers to send with the mail, in an
72: * associative array, where the array key is the
73: * header name (ie, 'Subject'), and the array
74: * value is the header value (ie, 'test'). The
75: * header produced from those values would be
76: * 'Subject: test'.
77: * If the '_raw' key exists, the value of this
78: * key will be used as the exact text for
79: * sending the message.
80: * @param mixed $body The full text of the message body, including
81: * any Mime parts, etc. Either a string or a
82: * stream resource.
83: *
84: * @throws Horde_Mail_Exception
85: */
86: public function send($recipients, array $headers, $body)
87: {
88: $headers = $this->_sanitizeHeaders($headers);
89:
90: // If we're passed an array of recipients, implode it.
91: if (is_array($recipients)) {
92: $recipients = array_map('trim', implode(',', $recipients));
93: }
94:
95: $subject = '';
96:
97: foreach (array_keys($headers) as $hdr) {
98: if (strcasecmp($hdr, 'Subject') === 0) {
99: // Get the Subject out of the headers array so that we can
100: // pass it as a separate argument to mail().
101: $subject = $headers[$hdr];
102: unset($headers[$hdr]);
103: } elseif (strcasecmp($hdr, 'To') === 0) {
104: // Remove the To: header. The mail() function will add its
105: // own To: header based on the contents of $recipients.
106: unset($headers[$hdr]);
107: }
108: }
109:
110: // Flatten the headers out.
111: list(, $text_headers) = $this->prepareHeaders($headers);
112:
113: // mail() requires a string for $body. If resource, need to convert
114: // to a string.
115: if (is_resource($body)) {
116: $body_str = '';
117:
118: stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol');
119: stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep));
120:
121: rewind($body);
122: while (!feof($body)) {
123: $body_str .= fread($body, 8192);
124: }
125: $body = $body_str;
126: } else {
127: // Convert EOL characters in body.
128: $body = $this->_normalizeEOL($body);
129: }
130:
131: // We only use mail()'s optional fifth parameter if the additional
132: // parameters have been provided and we're not running in safe mode.
133: if (empty($this->_params) || ini_get('safe_mode')) {
134: $result = mail($recipients, $subject, $body, $text_headers);
135: } else {
136: $result = mail($recipients, $subject, $body, $text_headers, isset($this->_params['args']) ? $this->_params['args'] : '');
137: }
138:
139: // If the mail() function returned failure, we need to create an
140: // Exception and return it instead of the boolean result.
141: if ($result === false) {
142: throw new Horde_Mail_Exception('mail() returned failure.');
143: }
144: }
145: }
146: