codes****@googl*****
codes****@googl*****
2009年 4月 25日 (土) 13:43:27 JST
Author: tacahi Date: Fri Apr 24 21:40:54 2009 New Revision: 1540 Modified: trunk/geeklog-1-jp-extended/system/custom/custom_mail_jp.php Log: * r1533〜r1536, r1538の変更を取り込みました。 - バージョン番号の判定に失敗するバグの修正 - 「ヘッダのエンコード方法」に ICONV_MIME_ENCODE を指定した場合に、 ヘッダの先頭に余分なコロンが付加されるバグの修正 - コメントにWikiのURIを追記 - タブをスペースに置き換え、行末の余分な空白を削除 Modified: trunk/geeklog-1-jp-extended/system/custom/custom_mail_jp.php ============================================================================== --- trunk/geeklog-1-jp-extended/system/custom/custom_mail_jp.php (original) +++ trunk/geeklog-1-jp-extended/system/custom/custom_mail_jp.php Fri Apr 24 21:40:54 2009 @@ -1,18 +1,18 @@ <?php -if (strpos(strtolower($_SERVER['PHP_SELF']), 'custom_mail_jp.php') !== false) { +if (strpos(strtolower($_SERVER['PHP_SELF']), 'custom_mail_jp.php') !== FALSE) { die('This file can not be used on its own!'); } // ================================================================== -// 日本語メール関数 +// 日本語メール関数 // // @summary Geeklog-1.4.1以降のメールを従来のISO-2022-JP(JIS) // メールに戻します。 // @author mystral-kk - geeklog AT mystral-kk DOT net // @license LGPL -// @version 2009-02-27 -// @note このハックが不要な場合は,system/lib-custom.phpの中の +// @version 2009-04-25 +// @note このハックが不要な場合は、system/lib-custom.phpの中の // require_once('custom/custom_mail_jp.php'); // を削除してください。 // ================================================================== @@ -22,28 +22,87 @@ // ・jpmailプラグインと同時に使用できません。先にjpmailプラグインをアンイン ス // トールしてください。 // -// ・$_CONF['mail_settings']['backend']に'mail'を指定すると,見出し(件名 )が -// 長い場合,Gmail等では正常に受け取れない場合があります。できるだけ, -// $_CONF['mail_settings']['backend']に'smtp'を指定してください(同時に, -// 'host', 'username', 'password'も指定します)。 +// ・メールが送れない場合や見出しなどが乱れる場合の対処法 // -// ・'smtp'にできない場合は,CUSTOM_MAIL_HEADER_LENGTHに400を指定してくださ い。 +// 最新情報は、http://wiki.geeklog.jp/index.php/CUSTOM_mail を参照してく ださ +// い。 +// +// 1. コンフィギュレーション - サイト - メール - メール設定[backend] +// (Geeklog-1.4.1では、config.phpの $_CONF['mail_settings']['backend']) +// を smtp に変えてみる。この場合、「メール設定[host]」、 +// 「メール設定[username]」、「メール設定[password]」なども設定する必要 があ +// ります(Geeklog-1.4.1では、それぞれ、config.phpの +// $_CONF['mail_settings']['host']、 $_CONF['mail_settings']['username']、 +// $_CONF['mail_settings']['password'])。 +// +// 2. 「メールヘッダの改行文字」を \n に変えてみる。 +// +// 3. 「ヘッダのエンコード方法」を ICONV_MIME_ENCODE や CUSTOM_ENCODE に 変え +// てみる。CUSTOM_ENCODEの場合は、「メールヘッダの1行の長さの最大値」 を既 +// 定値の76を大きくすることで改善される場合があります。 // -// ・それでも件名や差出人が乱れる場合は,下記の「メールヘッダの改行文字」の 項目 -// をご覧ください。 global $_CONF, $LANG_CHARSET; // デバッグ用 //define('CUSTOM_MAIL_DEBUG', true); -// メールヘッダ・本文で使用するエンコーディング。英語版の動作に戻すには -// define('CUSTOM_MAIL_ENCODING', 'UTF-8'); -// としてください。 - +/** +* メールヘッダ・本文で使用するエンコーディング +* +* 英語版の動作に戻すには +* define('CUSTOM_MAIL_ENCODING', 'utf-8'); +* としてください。 +*/ define('CUSTOM_MAIL_ENCODING', 'ISO-2022-JP'); +//define('CUSTOM_MAIL_ENCODING', 'utf-8'); + +/** +* ヘッダのエンコード方法 +* +* MB_ENCODE_MIMEHEADER: PHPのmb_encode_mimeheader()を使用する(既定値) +* ICONV_MIME_ENCODE: iconv_mime_encode()を使用する +* CUSTOM_ENCODE: mb_encode_mimeheader()が正常に動作しないPHPのバージ ョ +* ン(4.3.11, 4.4.0, 4.4.1, 5.0.0〜5.1.0など)用に独自 の +* エンコード方法を使用する +*/ +define('CUSTOM_MAIL_HEADER_ENCODE', 'MB_ENCODE_MIMEHEADER'); +//define('CUSTOM_MAIL_HEADER_ENCODE', 'ICONV_MIME_ENCODE'); +//define('CUSTOM_MAIL_HEADER_ENCODE', 'CUSTOM_ENCODE'); + +/** +* CUSTOM_ENCODEを使用する場合のメールヘッダの1行の長さの最大値 +* +* 既定値を変更する必要はまずないでしょう(上記の「ご注意」参照)。400 にす るのは、 +* 他の方法がうまくいかない場合の最終的な手段です。 +*/ +define('CUSTOM_MAIL_HEADER_LENGTH', 76); +//define('CUSTOM_MAIL_HEADER_LENGTH', 400); + +/** +* メールヘッダの改行文字 +* +* サーバの環境によってはメールの件名や差出人が乱れて、本文に流れ込むことが あり +* ます。その場合は \n にする必要があるかもしれません。特に「ヘッダのエン コード +* 方法」に CUSTOM_ENCODE を指定した場合は、\n にしないと動作しないことが多 いよ +* うです。 +*/ +//define('CUSTOM_MAIL_HEADER_LINEBREAK', "\n"); +define('CUSTOM_MAIL_HEADER_LINEBREAK', "\r\n"); -// Geeklogの内部エンコーディング。 +/** +* アドレスのコメント部分の引用符 +* +* 既定値はGeeklog本家版の動作に合わせてあります。 +*/ +define('CUSTOM_MAIL_COMMENT_ENCLOSER', '"'); // ""でくるむ +//define('CUSTOM_MAIL_COMMENT_ENCLOSER', ''); // 引用符なし + +/////////////////////////////////////////////////////////////////////////////// +// ここから下は変更しないでください。 +/////////////////////////////////////////////////////////////////////////////// + +// Geeklogの内部エンコーディング if (isset($LANG_CHARSET)) { define('CUSTOM_MAIL_INTERNAL_ENCODING', $LANG_CHARSET); @@ -53,81 +112,116 @@ define('CUSTOM_MAIL_INTERNAL_ENCODING', 'utf-8'); } -// メールヘッダの1行の長さの最大値。必ず4の倍数にします。 -// デフォルト値を変更する必要はまずないでしょう(上記の「ご注意」参照)。 - -define('CUSTOM_MAIL_HEADER_LENGTH', 68); -//define('CUSTOM_MAIL_HEADER_LENGTH', 400); - -// メールヘッダの改行文字。サーバの環境によってはメールの件名や差出人が -// 乱れることがあります。その場合は \n にする必要があるかもしれません。 - -define('CUSTOM_MAIL_HEADER_LINEBREAK', "\r\n"); -//define('CUSTOM_MAIL_HEADER_LINEBREAK', "\n"); - -// アドレスのコメント部分の引用符 - -define('CUSTOM_MAIL_COMMENT_ENCLOSER', '"'); - // 本文の改行文字 -define('CUSTOM_MAIL_BODY_LINEBREAK', - (substr(PHP_OS, 0, 3) == 'WIN' ? "\r\n" : "\n") -); +define('CUSTOM_MAIL_BODY_LINEBREAK', (substr(PHP_OS, 0, 3) == 'WIN') ? "\r\n" : "\n"); /** * Converts encoding */ -function CUSTOM_convertEncoding($string, $to_encoding) { - $from_encoding = @mb_detect_encoding( - $string, - array('UTF-8', 'eucJP-win', 'EUC-JP', 'SJIS-win', 'SJIS', 'ISO-8859-1', 'ASCII') - ); - +function CUSTOM_convertEncoding($string, $to_encoding, $from_encoding = NULL) { + if ($from_encoding === NULL) { + if (is_callable('mb_detect_encoding')) { + $from_encoding = @mb_detect_encoding( + $string, + array(CUSTOM_MAIL_INTERNAL_ENCODING, 'utf-8', 'eucjp-win', 'euc-jp', 'sjis-win', 'sjis', 'iso-8859-1', 'ascii') + ); + } + } + if (empty($from_encoding)) { $from_encoding = CUSTOM_MAIL_INTERNAL_ENCODING; } - - return mb_convert_encoding($string, $to_encoding, $from_encoding); + + if (is_callable('mb_convert_encoding')) { + return mb_convert_encoding($string, $to_encoding, $from_encoding); + } else if (is_callable('iconv')) { + return iconv($from_encoding, $to_encoding, $string); + } else { + COM_errorLog('CUSTOM_convertEncoding: no way to convert encoding.'); + return $string; + } } /** * Encodes a string such that it can be used in an email header * -* @param string $string the text to be encoded +* @param string $string the text to be encoded. The encoding should be +* the same as that of GL's internal encoding, +* which will returned from COM_getCharset(). * @return string encoded text -* */ function CUSTOM_emailEscape($string) { global $_CONF, $LANG_CHARSET; - + $retval = ''; - $string = CUSTOM_convertEncoding($string, CUSTOM_MAIL_INTERNAL_ENCODING); + if (defined('CUSTOM_MAIL_DEBUG')) { COM_errorLog('CUSTOM_emailEscape: input=' . $string); } - + + // PHPのmb_encode_mimeheader()を使用する場合 + if (CUSTOM_MAIL_HEADER_ENCODE == 'MB_ENCODE_MIMEHEADER') { + if (is_callable('mb_encode_mimeheader')) { + if (is_callable('mb_convert_encoding')) { + $string = mb_convert_encoding( + $string, CUSTOM_MAIL_ENCODING, CUSTOM_MAIL_INTERNAL_ENCODING + ); + } else { + COM_errorLog('CUSTOM_emailEscape: function mb_convert_encoding() not callable.'); + } + + $old_mb_internal_encoding = mb_internal_encoding(); + mb_internal_encoding(CUSTOM_MAIL_ENCODING); + $string = mb_encode_mimeheader($string, CUSTOM_MAIL_ENCODING, 'B', CUSTOM_MAIL_HEADER_LINEBREAK); + mb_internal_encoding($old_mb_internal_encoding); + + return $string; + } else { + COM_errorLog('CUSTOM_emailEscape: function mb_encode_mimeheader() not callable.'); + } + } + // ASCIIだけの場合は"(\x22)だけエスケープする if (!preg_match("/[^\\x00-\\x7f]/", $string)) { return str_replace('"', '\\"', $string); } - // mb_convert_encodingが使える場合 - if (function_exists('mb_convert_encoding')) { + // PHPのiconv_mime_encode()を使用する場合 + if (CUSTOM_MAIL_HEADER_ENCODE == 'ICONV_MIME_ENCODE') { + if (is_callable('iconv_mime_encode')) { + $prefs = array( + 'scheme' => 'B', + 'input-charset' => CUSTOM_MAIL_INTERNAL_ENCODING, + 'output-charset' => CUSTOM_MAIL_ENCODING, + 'line-length' => CUSTOM_MAIL_HEADER_LENGTH, + 'line-break-chars' => CUSTOM_MAIL_HEADER_LINEBREAK + ); + $string = iconv_mime_encode('subject', $string, $prefs); + $string = ltrim(substr($string, strpos($string, ':') + 1)); + + return $string; + } else { + COM_errorLog('CUSTOM_emailEscape: function iconv_mime_encode() not callable. Tries to use custom encoding method instead.'); + } + } + + // 独自のエンコード方法を使用する。従来の処理と同じ。 + if (is_callable('mb_convert_encoding')) { $string = mb_convert_encoding( $string, CUSTOM_MAIL_ENCODING, CUSTOM_MAIL_INTERNAL_ENCODING ); - + $len_mime = strlen('=?' . CUSTOM_MAIL_ENCODING . '?B?' . '?='); $cnt = strlen('Subject: '); $parts = array(); $old_mb_internal_encoding = mb_internal_encoding(); mb_internal_encoding(CUSTOM_MAIL_ENCODING); - + while ($string != '') { $maxlen = mb_strlen($string); $cut = $maxlen; - + for ($i = 1; $i <= $maxlen; $i ++) { $temp = base64_encode(mb_substr($string, 0, $i)); if (strlen($temp) + $len_mime + $cnt > CUSTOM_MAIL_HEADER_LENGTH) { @@ -141,31 +235,17 @@ $string = mb_substr($string, $cut); $cnt = 1; } - + mb_internal_encoding($old_mb_internal_encoding); $string = implode(CUSTOM_MAIL_HEADER_LINEBREAK . ' ', $parts); if (defined('CUSTOM_MAIL_DEBUG')) { COM_errorLog('CUSTOM_emailEscape: output=' . $string); } - + return $string; } - - // iconv()が使える場合 - if (function_exists('iconv_mime_encode')) { - $pref = array( - 'scheme' => 'B', - 'input-charset' => CUSTOM_MAIL_INTERNAL_ENCODING, - 'output-charset' => CUSTOM_MAIL_ENCODING, - 'line-length' => CUSTOM_MAIL_HEADER_LENGTH - ); - $retval = iconv_mime_encode('Subject', $string, $pref); - if ($retval !== false) { - return substr($retval, strlen('Subject: ')); - } - } - // iconvもmb_convert_encodingもなかった... + // どのエンコード方法も使用できなかった... COM_errorLog('CUSTOM_emailEscape: no function found to convert encodings.'); return $string; } @@ -183,7 +263,7 @@ if (empty($name)) { return $address; } - + $formatted_name = CUSTOM_emailEscape($name); if ($formatted_name == $name) { $formatted_name = str_replace('"', '\\"', $formatted_name); @@ -191,28 +271,30 @@ if (strlen('From: ' . $formatted_name . $address) > CUSTOM_MAIL_HEADER_LENGTH) { $address = CUSTOM_MAIL_HEADER_LINEBREAK . ' ' . $address; } - + $retval = CUSTOM_MAIL_COMMENT_ENCLOSER . $formatted_name . CUSTOM_MAIL_COMMENT_ENCLOSER . ' <' . $address . '>'; if (defined('CUSTOM_MAIL_DEBUG')) { COM_errorLog('CUSTOM_formatEmailAddress: output=' . $retval); } - + return $retval; } /** * Splits "comment <address>" into comment and address +* +* @note This function will not be called since Geeklog-1.5.2 */ function CUSTOM_splitAddress($string) { $comment = ''; $string = rtrim($string); - + if (substr($string, -1) != '>') { $address = $string; } else { $address = strrchr($string, '<'); - if ($address === false) { + if ($address === FALSE) { COM_errorLog('CUSTOM_splitAddress: "<" not found.'); $address = $string; } else { @@ -220,49 +302,47 @@ $address = substr($address, 1, strlen($address) - 2); } } - + if (defined('CUSTOM_MAIL_DEBUG')) { COM_errorLog('CUSTOM_splitAddress: comment=' . $comment . ' address=' . $address); } - + return array($comment, $address); } /** -* This is an example of a custom email function. When this function is NOT -* commented out, Geeklog would send all emails through this function -* instead of sending them through COM_mail in lib-common.php. -* -* This is basically a re-implementation of the way emails were sent -* prior to Geeklog 1.3.9 (Geeklog uses PEAR::Mail as of version 1.3.9). -* +* Custom email function for creating an email message in ISO-2022-JP */ function CUSTOM_mail($to, $subject, $message, $from = '', $html = false, $priority = 0, $cc = '') { global $_CONF, $LANG_CHARSET; - + static $mailobj; - + include_once 'Mail.php'; include_once 'Mail/RFC822.php'; - + if (defined('CUSTOM_MAIL_DEBUG')) { COM_errorLog('CUSTOM_mail: to=' . $to . ' subject=' . $subject); } - + // 余分なヘッダを追加されないように改行コードを削除 $to = substr($to, 0, strcspn($to, "\r\n")); $cc = substr($cc, 0, strcspn($cc, "\r\n")); $from = substr($from, 0, strcspn($from, "\r\n")); $subject = substr($subject, 0, strcspn($subject, "\r\n")); - - // Fromが空の場合は,サイト管理者のアドレスにする + + // Fromが空の場合は、サイト管理者のアドレスにする if (empty($from)) { $from = COM_formatEmailAddress($_CONF['site_name'], $_CONF['site_mail']); } - + // ヘッダをエスケープ(1.5.2では、この時点でエスケープ済み) - if (version_compare(VERSION, '1.5.2') < 0) { + // NOTE: version_compare(VERSION, '1.5.2')とすると、security releaseで は + // 判定に失敗する + preg_match("/^(\d+\.\d+\.\d+).*$/", VERSION, $match); + + if (version_compare($match[1], '1.5.2') < 0) { list($temp_to_comment, $temp_to_address) = CUSTOM_splitAddress($to); $to = CUSTOM_formatEmailAddress($temp_to_comment, $temp_to_address); list($temp_cc_comment, $temp_cc_address) = CUSTOM_splitAddress($cc); @@ -271,23 +351,23 @@ $from = CUSTOM_formatEmailAddress($temp_from_comment, $temp_from_address); $subject = CUSTOM_emailEscape($subject); } - + // 本文をエスケープ $message = CUSTOM_convertEncoding($message, CUSTOM_MAIL_ENCODING); $message = str_replace( array("\r\n", "\n", "\r"), CUSTOM_MAIL_BODY_LINEBREAK, $message ); - + // メールオブジェクトを作成 $method = $_CONF['mail_settings']['backend']; if (!isset($mailobj)) { - if ($method == 'sendmail' OR $method == 'smtp') { + if (($method == 'sendmail') OR ($method == 'smtp')) { $mailobj =& Mail::factory($method, $_CONF['mail_settings']); } else { $mailobj =& Mail::factory($method); } } - + // ヘッダ組み立て $headers = array(); @@ -318,9 +398,9 @@ $headers['X-Mailer'] = 'Geeklog-' . VERSION . ' (' . CUSTOM_MAIL_ENCODING . ')'; $retval = $mailobj->send($to, $headers, $message); - if($retval !== true) { + if($retval !== TRUE) { COM_errorLog($retval->toString(), 1); } - - return ($retval === true ? true : false); + + return (($retval === TRUE) ? TRUE : FALSE); }