OSDN Git Service

- deleted app/filter directory in creating new project.
[ethna/ethna.git] / class / Ethna_MailSender.php
1 <?php
2 // vim: foldmethod=marker
3 /**
4  *  Ethna_MailSender.php
5  *
6  *  @author     Masaki Fujimoto <fujimoto@php.net>
7  *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
8  *  @package    Ethna
9  *  @version    $Id$
10  */
11
12 /** メールテンプレートタイプ: 直接送信 */
13 define('MAILSENDER_TYPE_DIRECT', 0);
14
15
16 // {{{ Ethna_MailSender
17 /**
18  *  メール送信クラス
19  *
20  *  @author     Masaki Fujimoto <fujimoto@php.net>
21  *  @access     public
22  *  @package    Ethna
23  */
24 class Ethna_MailSender
25 {
26     /**#@+
27      *  @access private
28      */
29
30     /** @var    array   メールテンプレート定義 */
31     var $def = array(
32     );
33
34     /** @var    string  メールテンプレートディレクトリ */
35     var $mail_dir = 'mail';
36
37     /** @var    int     送信メールタイプ */
38     var $type;
39
40     /** @var    string  送信オプション */
41     var $option = '';
42
43     /** @var    object  Ethna_Backend   backendオブジェクト */
44     var $backend;
45
46     /** @var    object  Ethna_Config    設定オブジェクト */
47     var $config;
48
49     /**#@-*/
50
51     /**
52      *  Ethna_MailSenderクラスのコンストラクタ
53      *
54      *  @access public
55      *  @param  object  Ethna_Backend   &$backend       backendオブジェクト
56      */
57     function Ethna_MailSender(&$backend)
58     {
59         $this->backend =& $backend;
60         $this->config =& $this->backend->getConfig();
61     }
62
63     /**
64      *  メールオプションを設定する
65      *
66      *  @access public
67      *  @param  string  $option メール送信オプション
68      */
69     function setOption($option)
70     {
71         $this->option = $option;
72     }
73
74     /**
75      *  メールを送信する
76      *
77      *  $attach の指定方法:
78      *  - 既存のファイルを添付するとき
79      *  <code>
80      *  array('filename' => '/tmp/hoge.xls', 'content-type' => 'application/vnd.ms-excel')
81      *  </code>
82      *  - 文字列に名前を付けて添付するとき
83      *  <code>
84      *  array('name' => 'foo.txt', 'content' => 'this is foo.')
85      *  </code>
86      *  'content-type' 省略時は 'application/octet-stream' となる。
87      *  複数添付するときは上の配列を添字0から始まるふつうの配列に入れる。
88      *
89      *  @access public
90      *  @param  string  $to         メール送信先アドレス (nullのときは送信せずに内容を return する)
91      *  @param  string  $template   メールテンプレート名 or タイプ
92      *  @param  array   $macro      テンプレートマクロ or $templateがMAILSENDER_TYPE_DIRECTのときはメール送信内容)
93      *  @param  array   $attach     添付ファイル
94      */
95     function send($to, $template, $macro, $attach = null)
96     {
97         // メール内容を作成
98         if ($template === MAILSENDER_TYPE_DIRECT) {
99             $mail = $macro;
100         } else {
101             $renderer =& $this->getTemplateEngine();
102
103             // 基本情報設定
104             $env_datetime = _et('%Y/%m/%d %H:%M:%S');
105             $renderer->setProp("env_datetime", strftime($env_datetime));
106             $renderer->setProp("env_useragent", $_SERVER["HTTP_USER_AGENT"]);
107             $renderer->setProp("env_remoteaddr", $_SERVER["REMOTE_ADDR"]);
108
109             // デフォルトマクロ設定
110             $macro = $this->_setDefaultMacro($macro);
111
112             // ユーザ定義情報設定
113             if (is_array($macro)) {
114                 foreach ($macro as $key => $value) {
115                     $renderer->setProp($key, $value);
116                 }
117             }
118             if (isset($this->def[$template])) {
119                 $template = $this->def[$template];
120             }
121             $mail = $renderer->perform(sprintf('%s/%s', $this->mail_dir, $template), true);
122             if (Ethna::isError($mail)) {
123                 return $mail;
124             }
125         }
126         if ($to === null) {
127             return $mail;
128         }
129
130         // メール内容をヘッダと本文に分離
131         $mail = str_replace("\r\n", "\n", $mail);
132         list($header, $body) = $this->_parse($mail);
133
134         // 添付ファイル (multipart)
135         if ($attach !== null) {
136             $attach = isset($attach[0]) ? $attach : array($attach);
137             $boundary = Ethna_Util::getRandom(); 
138             $body = "This is a multi-part message in MIME format.\n\n" .
139                 "--$boundary\n" .
140                 "Content-Type: text/plain; charset=iso-2022-jp\n" .
141                 "Content-Transfer-Encoding: 7bit\n\n" .
142                 "$body\n";
143             foreach ($attach as $part) {
144                 if (isset($part['content']) === false
145                     && isset($part['filename']) && is_readable($part['filename'])) {
146                     $part['content'] = file_get_contents($part['filename']);
147                     $part['filename'] = basename($part['filename']);
148                 }
149                 if (isset($part['content']) === false) {
150                     continue;
151                 }
152                 if (isset($part['content-type']) === false) {
153                     $part['content-type'] = 'application/octet-stream';
154                 }
155                 if (isset($part['name']) === false) {
156                     $part['name'] = $part['filename'];
157                 }
158                 if (isset($part['filename']) === false) {
159                     $part['filename'] = $part['name'];
160                 }
161                 $part['name'] = preg_replace('/([^\x00-\x7f]+)/e',
162                     "Ethna_Util::encode_MIME('$1')", $part['name']); // XXX: rfc2231
163                 $part['filename'] = preg_replace('/([^\x00-\x7f]+)/e',
164                     "Ethna_Util::encode_MIME('$1')", $part['filename']);
165
166                 $body .=
167                     "--$boundary\n" .
168                     "Content-Type: " . $part['content-type'] . ";\n" .
169                         "\tname=\"" . $part['name'] . "\"\n" .
170                     "Content-Transfer-Encoding: base64\n" . 
171                     "Content-Disposition: attachment;\n" .
172                         "\tfilename=\"" . $part['filename'] . "\"\n\n";
173                 $body .= chunk_split(base64_encode($part['content']));
174             }
175             $body .= "--$boundary--";
176         }
177
178         // ヘッダ
179         if (isset($header['mime-version']) === false) {
180             $header['mime-version'] = array('Mime-Version', '1.0');
181         }
182         if (isset($header['subject']) === false) {
183             $header['subject'] = array('Subject', 'no subject in original');
184         }
185         if (isset($header['content-type']) === false) {
186             $header['content-type'] = array(
187                 'Content-Type',
188                 $attach === null ? 'text/plain; charset=iso-2022-jp'
189                                  : "multipart/mixed; \n\tboundary=\"$boundary\"",
190             );
191         }
192
193         $header_line = "";
194         foreach ($header as $key => $value) {
195             if ($key == 'subject') {
196                 // should be added by mail()
197                 continue;
198             }
199             if ($header_line != "") {
200                 $header_line .= "\n";
201             }
202             $header_line .= $value[0] . ": " . $value[1];
203         }
204
205         // 改行コードを CRLF に
206         if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
207             $body = str_replace("\n", "\r\n", $body);
208         }
209         $header_line = str_replace("\n", "\r\n", $header_line);
210
211         // 送信
212         foreach (to_array($to) as $rcpt) {
213             if (is_string($this->option)) {
214                 mail($rcpt, $header['subject'][1], $body, $header_line, $this->option);
215             } else {
216                 mail($rcpt, $header['subject'][1], $body, $header_line);
217             }
218         }
219     }
220
221     /**
222      *  アプリケーション固有のマクロを設定する
223      *
224      *  @access protected
225      *  @param  array   $macro  ユーザ定義マクロ
226      *  @return array   アプリケーション固有処理済みマクロ
227      */
228     function _setDefaultMacro($macro)
229     {
230         return $macro;
231     }
232
233     /**
234      *  テンプレートメールのヘッダ情報を取得する
235      *
236      *  @access private
237      *  @param  string  $mail   メールテンプレート
238      *  @return array   ヘッダ, 本文
239      */
240     function _parse($mail)
241     {
242         list($header_line, $body) = preg_split('/\r?\n\r?\n/', $mail, 2);
243         $header_line .= "\n";
244
245         $header_lines = explode("\n", $header_line);
246         $header = array();
247         foreach ($header_lines as $h) {
248             if (strstr($h, ':') == false) {
249                 continue;
250             }
251             list($key, $value) = preg_split('/\s*:\s*/', $h, 2);
252             $i = strtolower($key);
253             $header[$i] = array();
254             $header[$i][] = $key;
255             $header[$i][] = preg_replace('/([^\x00-\x7f]+)/e', "Ethna_Util::encode_MIME('$1')", $value);
256         }
257
258         $body = mb_convert_encoding($body, "ISO-2022-JP");
259
260         return array($header, $body);
261     }
262
263     /**
264      *  メールフォーマット用レンダラオブジェクト取得する
265      *
266      *  @access public
267      *  @return object  Ethna_Renderer  レンダラオブジェクト
268      */
269     function &getRenderer()
270     {
271         $_ret_object =& $this->getTemplateEngine();
272         return $_ret_object;
273     }
274
275     /**
276      *  メールフォーマット用レンダラオブジェクト取得する
277      *
278      *  @access public
279      *  @return object  Ethna_Renderer  レンダラオブジェクト
280      */
281     function &getTemplateEngine()
282     {
283         $c =& $this->backend->getController();
284         $renderer =& $c->getRenderer();
285         return $renderer;
286     }
287 }
288 // }}}
289 ?>