MyMiniCity踏んでください!!

ただいま絶賛MyMiniCity参加中です.是非リンクを踏んでください!!(笑
February 15th, 2006

PHPのmail()のできの悪さ

(Read: 447549)
Add to Hatena Bookmark

参照: [cvs] Log of /php/src/ext/standard/mail.c
大分読めるようになったので改めてメモ.
どうにも頭の悪い実装をしている.
bugs.php.netに書くのも面倒くさい…

SKIP_LONG_HEADER_SEPはこれ.
ようするに「\r\n[ \t\+]」な文字列を飛ばします.


#define SKIP_LONG_HEADER_SEP(str, pos) \
if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) { \
pos += 3; \
while (str[pos] == ' ' || str[pos] == '\t') { \
pos++; \
} \
continue; \
} \
第1引数を処理する辺り.
ようするに不当な制御コードをここで落とします.ただし上記マクロを使って「改行」+「行頭の空白」は例外とします.


if (to_len > 0) {
to_r = estrndup(to, to_len);
for (; to_len; to_len--) {
if (!isspace((unsigned char) to_r[to_len - 1])) {
break;
}
to_r[to_len - 1] = '\0';
}
for (i = 0; to_r[i]; i++) {
if (iscntrl((unsigned char) to_r[i])) {
/* According to RFC 822, section 3.1.1 long headers may be separated into
* parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
* To prevent these separators from being replaced with a space, we use the
* SKIP_LONG_HEADER_SEP to skip over them.
*/
SKIP_LONG_HEADER_SEP(to_r, i);
to_r[i] = ' ';
}
}
} else {
to_r = to;
}
mail()のマニュアルを読んでもわかるのですが,
この関数は改行コードを2種類使い分けなければいけなくて,

・第3引数のメッセージ本文の改行はLF(\n)で行うこと
・第4引数の$additional_headersの改行はCR+LF(\r\n)で行うこと

となっています.頭悪いですね.一応$toもメール的にはヘッダーなので
$additional_headersと同等に「\r\n」で改行を表現します.
日本語メールとしてはmb_encode_mimeheader()を改行コードをいじらずに使用すればその状態になります.

ちなみに第2引数の$subjectも同様のフィルタリングが行われます.
で,Windows以外はphp_mail()という内部関数が実行されます.
ここのコードを読んでみましょう.


fprintf(sendmail, "To: %s\n", to);
fprintf(sendmail, "Subject: %s\n", subject);
if (headers != NULL) {
fprintf(sendmail, "%s\n", headers);
} fprintf(sendmail, "\n%s\n", message);
ret = pclose(sendmail);
お分かりでしょうか.改行コードはLF(\n)が使用されています.
そうです改行コードが複数混在です.
バカですね.

ちなみにWindowsは独自にSMTP処理が組み込まれた関数がwin32/sendmail.cに実装されています.
説明は面倒なので省くと(苦笑 こちらの方がとてもまともな実装をしています.

・内部関数php_win32_mail_trim_header()にて$additional_headersのフィルタリング
- 改行コード修正(LF/CRのCR+LF化)
- ダブル改行の除去
・内部関数PostHeader()にてDateフィールドが存在しない場合,自前で生成して付加

Content-Typeとかも吐いてくれてもいいじゃないかとか思うけど余計なおせっかいかもしれない.
ただしUNIX系でsendmailコマンドで処理されるメールより適当なテキストでもそこそこまともなメールを生成します.

メール送信はmail()と,とあるひとつの理由だけで使い勝手のあるmb_send_mail()とを常用してたけどなんかmail()も嫌になってきた.

ちなみにmail()がどんなメールテキストを生成してるかはこういう手順を踏むと簡単です.
PEAR::MailやphpMailerもi18n的には問題あるしどうしたものか.

$ echo "#!/bin/sh" > mail.sh
$ echo "cat - > mail.txt" >> mail.sh
$ php -d "sendmail_path=./mail.sh" -r 'mail( "foo@example.com", "foo\r\n foo\n foo\nfoo", "body", "From: foo@example.com\r\nX-Foo: foo\nX-Bar: bar");'
$ od -tx1 mail.txt
0000000 54 6f 3a 20 66 6f 6f 40 65 78 61 6d 70 6c 65 2e
0000020 63 6f 6d 0a 53 75 62 6a 65 63 74 3a 20 66 6f 6f
0000040 0d 0a 20 66 6f 6f 20 20 66 6f 6f 20 66 6f 6f 0a
0000060 46 72 6f 6d 3a 20 66 6f 6f 40 65 78 61 6d 70 6c
0000100 65 2e 63 6f 6d 0d 0a 58 2d 46 6f 6f 3a 20 66 6f
0000120 6f 0a 58 2d 42 61 72 3a 20 62 61 72 0a 0a 62 6f
0000140 64 79 0a
;

トピックの参照元

▼最近のトピック

▼ 人気のトピック


< 過去の記事 [ 1月の All Categories リスト ] 新しい記事 >
Powered by gsblog (customize)

[ POST ] [ AddLink ] [ CtlPanel ]

Subscribe blog

Bookmark blog

About me

about me

応援しています

我が息子が産まれたアクア・バースハウス(東京都世田谷区にある助産院)を応援しています.

翻訳のお仕事

腕に自信がある方,修行をしたい方はこちらをどうぞ.

2020 calendar

1月
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
| Day | Month | Year |

Powered by RRDTOOL.

Archives

Categories

Links


Mail to admin

人気ブログランキングへ RSS feed meter for http://blog.poyo.jp/ Search Engine Optimization
blogpeople.netに登録!! スカウター : よくきたblog

My Google news

My Google News

Related site

ころんころん♪ べびぽよ フォト蔵Wiki
string(40) "/categ-1/year-2020/month-1/id-1139994430"