ここの情報は古いです。ご理解頂いた上でお取り扱いください。

source: OpenPNE/trunk/webapp/lib/OpenPNE/KtaiMail.php @ 4864

Last change on this file since 4864 was 4864, checked in by ebihara, 13 years ago

#1711:絵文字メール投稿処理に関係ない変更を削除し、au端末からのメール投稿かどうかをメールアドレスのドメインを見るように修正

File size: 12.5 KB
Line 
1<?php
2/**
3 * @copyright 2005-2007 OpenPNE Project
4 * @license   http://www.php.net/license/3_01.txt PHP License 3.01
5 * @author Ogawa ogawa@tejimaya.com
6 * @author Masaki Miyashita miyasita@zenzy.net
7 */
8
9// PEAR::Mail_mimeDecode
10require_once 'Mail/mimeDecode.php';
11require_once 'util.inc.php';
12
13/**
14 * OpenPNE_KtaiMail
15 * 携帯メール用のメールデコーダ
16 */
17class OpenPNE_KtaiMail
18{
19    /**
20     * デコード結果
21     * @var stdClass
22     */ 
23    var $mail;
24
25    /** @var string 変換元文字エンコーディング(デフォルト値) */
26    var $from_encoding = 'auto';
27
28    /** @var string 変換先文字エンコーディング */
29    var $to_encoding = 'UTF-8';
30
31    /** @var string 画像検証用のテンポラリディレクトリ */
32    var $img_tmp_dir;
33
34    /** @var string 画像検証用のテンポラリファイルの接頭辞 */
35    var $img_tmp_prefix = 'OpenPNE_KtaiMail_';
36
37    /** @var string 画像の最大ファイルサイズ(byte) */
38    var $img_max_filesize;
39
40    /** @var bool 全角スペースを削除するかどうか */
41    var $trim_doublebyte_space = true;
42
43    /**
44     * constructor
45     *
46     * @access public
47     * @param string $options
48     *      - from_encoding    : 変換元文字エンコーディング
49     *      - to_encoding      : 変換先文字エンコーディング
50     *      - img_tmp_dir      : 画像検証用のテンポラリディレクトリ
51     *      - img_tmp_prefix   : 画像検証用のテンポラリファイルの接頭辞
52     *      - img_max_filesize : 画像の最大ファイルサイズ
53     *      - trim_doublebyte_space : 全角スペースを削除するかどうか
54     */
55    function OpenPNE_KtaiMail($options = array())
56    {
57        foreach ($options as $key => $value) {
58            switch ($key) {
59            case 'from_encoding':
60                $this->from_encoding = $value;
61                break;
62            case 'to_encoding':
63                $this->to_encoding = $value;
64                break;
65            case 'img_tmp_dir':
66                $this->img_tmp_dir = $value;
67                break;
68            case 'img_tmp_prefix':
69                $this->img_tmp_prefix = $value;
70                break;
71            case 'img_max_filesize':
72                $this->img_max_filesize = $value;
73                break;
74            case 'trim_doublebyte_space':
75                $this->trim_doublebyte_space = (bool)$value;
76                break;
77            }
78        }
79    }
80
81    /**
82     * メールをデコード
83     *
84     * @access public
85     * @param string メールの生データ
86     */
87    function decode($raw_mail)
88    {
89        $params['include_bodies'] = true;
90        $params['decode_bodies']  = true;
91        $params['decode_headers'] = true;
92        $params['input'] = $raw_mail;
93
94        $this->mail =& Mail_mimeDecode::decode($params);
95    }
96
97    /**
98     * ヘッダー(From:)から送信元メールアドレスを取得
99     *
100     * @access public
101     * @return string Fromメールアドレス
102     */
103    function get_from()
104    {
105        return $this->_get_mail_address($this->mail->headers['from']);
106    }
107
108    /**
109     * ヘッダー(To:)から宛先メールアドレスを取得
110     *
111     * @access public
112     * @return string Toメールアドレス
113     */
114    function get_to()
115    {
116        return $this->_get_mail_address($this->mail->headers['to']);
117    }
118
119    /**
120     * Subject の内容を抽出(+文字コード変換)
121     *
122     * @access public
123     * @return string Subject
124     */
125    function get_subject()
126    {
127        return isset($this->mail->headers['subject']) ?
128                    $this->convert_text($this->mail->headers['subject']) : '';
129    }
130
131    /**
132     * メール本文からテキストを抽出(+文字コード変換)
133     *
134     * @access public
135     * @return string メール本文のテキスト
136     */
137    function get_text_body()
138    {
139        return $this->_get_text_body($this->mail);
140    }
141
142    /** @access private */
143    function _get_text_body(&$mail)
144    {
145        $body = '';
146
147        if (isset($mail->parts) && is_array($mail->parts)) {
148            // multipart
149            foreach ($mail->parts as $part) {
150                if ($body = $this->_get_text_body($part)) break;
151            }
152        } elseif (strtolower($mail->ctype_primary) === 'text' &&
153                  strtolower($mail->ctype_secondary) === 'plain') {
154            $body = $mail->body;
155            $charset = $mail->ctype_parameters['charset'];
156
157            $body = $this->convert_text($body, $charset);
158        }
159
160        return $body;
161    }
162
163    /**
164     * メールから画像データを抽出
165     *
166     * @access public
167     * @return array 画像データ配列
168     */
169    function get_images()
170    {
171        return $this->_get_images($this->mail);
172    }
173
174    /** @access private */
175    function _get_images(&$mail)
176    {
177        $allowed_type = array('jpeg', 'gif', 'png');
178        $images = array();
179
180        if (isset($mail->parts) && is_array($mail->parts)) {
181            // multipart
182            foreach ($mail->parts as $part) {
183                $images = array_merge($images, $this->_get_images($part));
184            }
185        } elseif (strtolower($mail->ctype_primary) === 'image' &&
186                  in_array(strtolower($mail->ctype_secondary), $allowed_type)) {
187            $image_data = $mail->body;
188            $image_ext = '';
189
190             // 画像かどうかチェック
191            if (!@imagecreatefromstring($image_data)) {
192                // base64_decodeしてリトライ
193                $image_data = base64_decode($image_data);
194                if (!@imagecreatefromstring($image_data)) {
195                    return array();
196                }
197            }
198
199            // 一時ファイルを作成
200            $tmpfname = tempnam($this->img_tmp_dir, $this->img_tmp_prefix);
201
202            $fp = fopen($tmpfname, 'wb');
203            fwrite($fp, $image_data);
204            fclose($fp);
205
206            // 画像サイズのチェック
207            if ($this->img_max_filesize && filesize($tmpfname) > $this->img_max_filesize) {
208                unlink($tmpfname);
209                return array();
210            }
211
212            // 画像のリサイズ
213            list($width, $height, $type, $attr) = @getimagesize($tmpfname);
214            $need_resize = false;
215            $original_width = $width;
216            $original_height = $height;
217            //横のサイズが、指定されたサイズより大きい場合
218            if (IMAGE_MAX_WIDTH && ($width > IMAGE_MAX_WIDTH)) {
219                $need_resize = true;
220                $height = $height * (IMAGE_MAX_WIDTH / $width);
221                $width = IMAGE_MAX_WIDTH;
222            }
223            //縦サイズが、指定されたサイズより大きい場合
224            if (IMAGE_MAX_HEIGHT && ($height > IMAGE_MAX_HEIGHT)) {
225                $need_resize = true;
226                $width = $width * (IMAGE_MAX_HEIGHT / $height);
227                $height = IMAGE_MAX_HEIGHT;
228            }
229            if ($height < 1.) {
230                $height = 1;
231            }
232            if ($width < 1.) {
233                $width = 1;
234            }
235            if ($need_resize) {
236                resize_image($type, $tmpfname, $tmpfname, $original_width, $original_height, $width, $height);
237                $fp = fopen($tmpfname, 'rb');
238                $image_data = fread($fp, filesize($tmpfname));  // 一時ファイルを再度読み込み
239                fclose($fp);
240            }
241
242            // 画像が正しいかどうかチェック
243            switch (strtolower($mail->ctype_secondary)) {
244            case 'jpeg':
245                if (!@imagecreatefromjpeg($tmpfname)) {
246                    $image_data = '';
247                } else {
248                    $image_ext = 'jpg';
249                }
250                break;
251            case 'gif':
252                if (!@imagecreatefromgif($tmpfname)) {
253                    $image_data = '';
254                } else {
255                    $image_ext = 'gif';
256                }
257                break;
258            case 'png':
259                if (!@imagecreatefrompng($tmpfname)) {
260                    $image_data = '';
261                } else {
262                    $image_ext = 'png';
263                }
264                break;
265            }
266            unlink($tmpfname);
267
268            if ($image_data && $image_ext) {
269                $images = array(array('data' => $image_data, 'ext' => $image_ext));
270            }
271        }
272
273        return $images;
274    }
275
276    /**
277     * 文字列からメールアドレスを抽出
278     *
279     * @access private
280     * @param string $str 入力文字列
281     * @return string メールアドレス
282     */
283    function _get_mail_address($str)
284    {
285        if (!$str) {
286            return false;
287        }
288
289        // "(ダブルクォーテーション)を取り除く
290        // "example"@docomo.ne.jp
291        $str = str_replace('"', '', $str);
292
293        // <example@docomo.ne.jp> というメールアドレスになることがある。
294        //   日本語 <example@docomo.ne.jp>
295        // のような場合に複数マッチする可能性があるので、
296        // マッチした最後のものを取ってくるように変更
297        $matches = array();
298        $regx = '/([\.\w!#$%&\'*+\-\/=?^`{|}~]+@[\w!#$%&\'*+\-\/=?^`{|}~]+(\.[\w!#$%&\'*+\-\/=?^`{|}~]+)*)/';
299        if (preg_match_all($regx, $str, $matches)) {
300            return array_pop($matches[1]);
301        }
302
303        return false;
304    }
305
306    function convert_text_core($str)
307    {
308        $converted_text = "";
309        $res = preg_split("/JIS\+..../", $str, -1, PREG_SPLIT_OFFSET_CAPTURE);
310
311        for ($i = 0; $i < count($res); $i++) {
312            if ($i == 0) {
313                $begin = strlen($res[$i][0]);
314                $converted_text .= $res[$i][0];
315            } else {
316                $jis = substr($str, $begin, 8);
317
318                // $jisを変換
319                $a = "0x" . substr($jis, 4, 2);
320                $b = "0x" . substr($jis, 6, 2);
321
322                // http://www.slayers.ne.jp/~oouchi/code/jistosjis.html
323                $a = intval($a, 16);
324                $b = intval($b, 16);
325                if ($a % 2 == 1) {
326                    $b += 0x1f;
327                } else {
328                    $b += 0x7d;
329                }
330
331                if ($b >= 0x7f) {
332                    $b++;
333                }
334
335                $a = floor(($a-0x21) / 2) + 0x81;
336
337                if ($a >= 0x9e) {
338                    $a+=0x40;
339                }
340
341                $c = $a * 16 * 16 + $b;
342                if ($c >= 0xEDCF || ($c >= 0xED40 && $c <= 0xEDCE)) {
343                    $c += 1536;
344                } else {
345                    $c += 2816;
346                }
347
348                // 絵文字変換
349                $bin[0] = chr($c >> 8);
350                $bin[1] = chr($c - ($bin[0] << 8));
351                $emoji = emoji_escape_e($bin);
352
353                $converted_text .= $emoji;
354
355                //Eメール送出用Shift-JIS(E-SJIS)と携帯用Shift-JISコード(K-SJIS)には以下の関係がある
356                // * 358 <= 絵文字番号 <= 499, 700 <= 絵文字番号
357                // hexdec(K-SJIS) = hexdec(E-SJIS) + 1536
358                // * それ以外の絵文字
359                // hexdec(K-SJIS) = hexdec(E-SJIS) + 2816
360                $begin = strlen($res[$i][0]) + $res[$i][1];
361                $converted_text .= $res[$i][0];
362            }
363        }
364        return $converted_text;
365    }
366 
367    /**
368     * 文字エンコーディングの変換、空白文字の削除
369     *
370     * @access public
371     * @param string $str 変換前の文字列
372     * @param string $from_encoding
373     * @param string $to_encoding
374     * @return string 変換後の文字列
375     */
376    function convert_text($str, $from_encoding = '', $to_encoding = '')
377    {
378        if (!$from_encoding) {
379            $from_encoding = $this->from_encoding;
380        }
381
382        if (!$to_encoding) {
383            $to_encoding = $this->to_encoding;
384        }
385
386        $from_addr = explode('@', $this->get_from());
387        $domain = array_pop($from_addr);
388
389        if ($domain == 'ezweb.ne.jp') {
390            mb_substitute_character("long");
391            $str = mb_convert_encoding($str, $to_encoding, $from_encoding);
392            $str = $this->convert_text_core($str);
393        } else {
394            $str = mb_convert_encoding($str, $to_encoding, $from_encoding);
395        }
396
397        // 空白文字の削除
398        $str = str_replace("\0", '', $str);
399        if ($this->trim_doublebyte_space) {
400            $str = mb_ereg_replace('([\s ])+$', '', $str);
401        } else {
402            $str = rtrim($str);
403        }
404
405        return $str;
406    }
407}
408
409?>
Note: See TracBrowser for help on using the repository browser.