php邮件送信类
クラスSMTP
{
/**
* SMTPサーバーポート
* @var int
*/
var $SMTP_PORT = 25;
/**
* SMTP 返信行の終了
* @var 文字列
*/
var $CRLF = "rn";
/**
* デバッグをオンにするかどうかを設定します
* @var bool
*/
var $do_debug; # 実行するデバッグのレベル
/**#@+
* @アクセス非公開
*/
var $smtp_conn; # サーバーへのソケット
var $error; # 最後の呼び出しでエラーがあった場合
var $helo_rply; # サーバーが HELO に送信した応答
/**#@-*/
/**
* データが既知の状態になるようにクラスを初期化します。
* @アクセス公開
* @return void
*/
関数 SMTP() {
$this->smtp_conn = 0;
$this->error = null;
$this->helo_rply = null;
$this->do_debug = 0;
}
/*************************************************** *********
* 接続機能 *
************************************************* *********/
/**
* 指定されたポートで指定されたサーバーに接続します。
* ポートが指定されていない場合は、デフォルトの SMTP_PORT を使用します。
* tval が指定されている場合、接続が試行されます
* その秒数の間、サーバーとの接続が確立されました。
* tval が指定されていない場合、デフォルトは 30 秒です
* 接続を試してください。
*
* SMTP コード成功: 220
* SMTP コードのエラー: 421
* @アクセス公開
* @return bool
*/
関数 Connect($host,$port=0,$tval=30) {
# 混乱しないようにエラー val を null に設定します
$this->error = null;
# __接続__されていないことを確認してください
if($this->connected()) {
#よし、つながった!どうしたらいいでしょうか?
# 今のところは、「we
」というエラーを表示するだけです
# はすでに接続されています
$this->エラー=
array("error" => "すでにサーバーに接続されています");
false を返します;
}
if(empty($port)) {
$port = $this->SMTP_PORT;
}
#SMTP サーバーに接続します
$this->smtp_conn = fsockopen($host, # サーバーのホスト
$port, # 使用するポート
$errno, # エラー番号がある場合は
$errstr, # エラー メッセージがある場合は
$tval); # 後は諦める?秒
# 正しく接続されていることを確認してください
if(empty($this->smtp_conn)) {
$this->error = array("error" => "サーバーへの接続に失敗しました",
"エラー番号" => $エラー、
"errstr" => $errstr);
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
": $errstr ($errno)" 。 $this->CRLF;
}
false を返します;
}
# SMTP サーバーの応答に少し時間がかかる場合があります
# そのため、最初の読み取りのタイムアウトを長くします
// Windows はまだこのタイムアウト関数をサポートしていません
if(substr(PHP_OS, 0, 3) != "WIN")
ソケット_セット_タイムアウト($this->smtp_conn, $tval, 0);
# お知らせ情報を入手します
$announce = $this->get_lines();
# ソケット関数のタイムアウトを 1/10 秒に設定します
//if(function_exists("socket_set_timeout"))
// socket_set_timeout($this->smtp_conn, 0, 100000);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $発表;
}
true を返す;
}
/**
※SMTP認証を行います。
を実行した後に実行する必要があります
* Hello() メソッド。 認証に成功した場合は true を返します。
* @アクセス公開
* @return bool
*/
関数 Authenticate($username, $password) {
// 認証を開始します
fputs($this->smtp_conn,"認証ログイン" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($code != 334) {
$this->エラー=
array("error" => "サーバーから AUTH が受け入れられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
// エンコードされたユーザー名を送信します
fputs($this->smtp_conn, Base64_encode($username) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($code != 334) {
$this->エラー=
array("error" => "ユーザー名がサーバーから受け入れられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
// エンコードされたパスワードを送信します
fputs($this->smtp_conn, Base64_encode($password) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($code != 235) {
$this->エラー=
array("error" => "パスワードがサーバーから受け入れられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
true を返す;
}
/**
* サーバーに接続されている場合は true を返し、それ以外の場合は false を返します
* @アクセス非公開
* @return bool
*/
関数 Connected() {
if(!empty($this->smtp_conn)) {
$sock_status =ソケット_get_status($this->smtp_conn);
if($sock_status["eof"]) {
# うーん、これは奇妙な状況ですね...ソケットは
# 有効ですが、もう接続されていません
if($this->do_debug >= 1) {
echo "SMTP -> 通知:" 。 $this->CRLF .
「接続されているかどうかの確認中に EOF をキャッチしました」;
}
$this->Close();
false を返します;
}
true を返します。 #すべてが良さそうです
}
false を返します;
}
/**
* ソケットを閉じてクラスの状態をクリーンアップします。
※この機能を使わずに使用するのは良くありません
* 最初に QUIT を使用してみます。
* @アクセス公開
* @return void
*/
関数 Close() {
$this->error = null; #混乱しないように
$this->helo_rply = null;
if(!empty($this->smtp_conn)) {
# 接続を閉じてクリーンアップします
fclose($this->smtp_conn);
$this->smtp_conn = 0;
}
}
/*************************************************** ***********
* SMTP コマンド *
************************************************* ***********/
/**
* data コマンドを発行し、msg_data をサーバーに送信します
*メール取引を完了します。 $msg_data はメッセージです
* ヘッダーと一緒に送信されます。各ヘッダーは次のようにする必要があります
* を 1 行に記述し、その後に
* とメッセージ本文は追加の
*
* rfc 821: DATA
*
* SMTP コード中間: 354
* [データ]
*
* SMTP コード成功: 250
* SMTP コードのエラー: 552,554,451,452
* SMTP コードのエラー: 451,554
* SMTP コード エラー : 500,501,503,421
* @アクセス公開
* @return bool
*/
関数データ($msg_data) {
$this->error = null; #混乱が起こらないように
if(!$this->connected()) {
$this->error = array(
「エラー」=> "接続せずに Data() を呼び出しました");
false を返します;
}
fputs($this->smtp_conn,"DATA" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
if($code != 354) {
$this->エラー=
array("error" => "DATA コマンドがサーバーから受け付けられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
# サーバーはデータを受け入れる準備ができています!
# rfc 821 によれば、1000 を超える送信はすべきではありません
# CRLF を含む
# 文字が 1 行に含まれるため、データを分割します
# r および/または n で行に分割し、必要に応じて分割します
# それぞれを制限内に収まるように小さな行に分割します。
# さらに、
で始まる行も探します
# ピリオド「.」ピリオド「.」を追加します。それに
# ライン。注: これは制限にはカウントされません。
# 爆発が機能することがわかるように改行を正規化します
$msg_data = str_replace("rn","n",$msg_data);
$msg_data = str_replace("r","n",$msg_data);
$lines =explode("n",$msg_data);
# ヘッダーが
であるかどうかを判断する良い方法を見つける必要があります
# msg_data 内、またはそれが直接の msg body の場合
# 現在、メッセージヘッダーの rfc 822 定義を想定しています
# そして最初の行の最初のフィールド (':' が区切られている) の場合
# スペースが含まれていない場合は、ヘッダーである必要があります
# そして空の "" 行の前のすべての行を次のように処理できます
# ヘッダー。
$field = substr($lines[0],0,strpos($lines[0],":"));
$in_headers = false;
if(!empty($field) && !strstr($field," ")) {
$in_headers = true;
}
$max_line_length = 998; # 以下で使用します。簡単に変更できるようにここに設定します
while(list(,$line) = @each($lines)) {
$lines_out = null;
if($line == "" && $in_headers) {
$in_headers = false;
}
# OK、この行をいくつかに分割する必要があります
# 小さい線
while(strlen($line) > $max_line_length) {
$pos = strrpos(substr($line,0,$max_line_length)," ");
$lines_out[] = substr($line,0,$pos);
$line = substr($line,$pos + 1);
# ヘッダーを処理している場合は
する必要があります
# 新しい行の先頭に LWSP 文字を追加します
# 長いメッセージヘッダーの rfc 822
if($in_headers) {
$line = "t" 。 $line;
}
}
$lines_out[] = $line;
# 次に行をサーバーに送信します
while(list(,$line_out) = @each($lines_out)) {
if(strlen($line_out) > 0)
{
if(substr($line_out, 0, 1) == ".") {
$line_out = "。" 。 $line_out;
}
}
fputs($this->smtp_conn,$line_out . $this->CRLF);
}
}
# OK、すべてのメッセージデータが送信されたので、これを取得しましょう
#もう終わり
fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
if($code != 250) {
$this->エラー=
array("error" => "サーバーからデータが受け入れられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
true を返します;
}
/** if(!$this->connected()) { fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF); $rply = $this->get_lines(); if($this->do_debug >= 2) { if($code != 250) { # 応答を解析し、ユーザーに返す配列に配置します $list を返す; /** if(!$this->connected()) { # HELO のホスト名が指定されていない場合は決定 // 最初に拡張 hello を送信する (RFC 2821) true を返す; /** $rply = $this->get_lines(); if($this->do_debug >= 2) { if($code != 250) { $this->helo_rply = $rply; /** if(!$this->connected()) { $extra = ""; fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF); $rply = $this->get_lines(); if($this->do_debug >= 2) { if($code != 211 && $code != 214) { $rply を返す; /** if(!$this->connected()) { $rply = $this->get_lines(); if($code != 250) { /** if(!$this->connected()) { fputs($this->smtp_conn,"NOOP" . $this->CRLF); $rply = $this->get_lines(); if($this->do_debug >= 2) { if($code != 250) { /** if(!$this->connected()) { # 終了コマンドをサーバーに送信します # お別れのメッセージを受け取ります if($this->do_debug >= 2) { $rval = true; $code = substr($byemsg,0,3); if(empty($e) || $close_on_error) { return $rval; /** if(!$this->connected()) { fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); $rply = $this->get_lines(); if($this->do_debug >= 2) { if($code != 250 && $code != 251) { /** if(!$this->connected()) { fputs($this->smtp_conn,"RSET" . $this->CRLF); $rply = $this->get_lines(); if($this->do_debug >= 2) { if($code != 250) { true を返す; /** if(!$this->connected()) { fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF); $rply = $this->get_lines(); if($this->do_debug >= 2) { if($code != 250) { /**
* Expand は名前を受け取り、サーバーにすべてのリストを要求します
* _list_ のメンバーである人々。展開すると戻ります
* 戻り値と結果の配列、またはエラーが発生した場合は false。
* 返される配列内の各値の形式は次のとおりです:
* [
* の定義rfc 821で定義されています
*
* rfc 821 を実装: EXPN
*
* SMTP コード成功: 250
* SMTP コードのエラー: 550
* SMTP コード エラー : 500,501,502,504,421
* @アクセス公開
* @return 文字列配列
*/
関数 Expand($name) {
$this->error = null; #混乱が起こらないように
$this->error = array(
「エラー」=> "接続されていないのに Expand() が呼び出されました");
false を返します;
}
$code = substr($rply,0,3);
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => "EXPN がサーバーから受け入れられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
$entries =explode($this->CRLF,$rply);
while(list(,$l) = @each($entries)) {
$list[] = substr($l,4);
}
}
* HELO コマンドを SMTP サーバーに送信します。
* これにより、私たちとサーバーが確実に存在するようになります
* 同じ既知の状態です
*
* rfc 821 からの実装: HELO
*
* SMTP コード成功: 250
* SMTP コード エラー: 500、501、504、421
* @アクセス公開
* @return bool
*/
関数 Hello($host="") {
$this->error = null; #混乱が起こらないように
$this->error = array(
「エラー」=> "接続されていないのに Hello() が呼び出されました");
false を返します;
}
#送るのに適したもの
if(空($host)) {
# 何らかの適切なデフォルトを決定する必要があります
# サーバーに送信します
$host = "ローカルホスト";
}
if(!$this->SendHello("EHLO", $host))
{
if(!$this->SendHello("HELO", $host))
false を返します;
}
}
* HELO/EHLO コマンドを送信します。
* @アクセス非公開
* @return bool
*/
関数 SendHello($hello, $host) {
fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
$code = substr($rply,0,3);
echo "SMTP -> FROM SERVER: " 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => $hello . " サーバーから受け付けられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
true を返します;
}
* 指定されたキーワードに関するヘルプ情報を取得します。キーワードなら
* が指定されていない場合は、一般的なヘルプ (通常は継続) が返されます
* 役立つキーワードのリストが利用可能です。この機能
* 結果をユーザーに返します。それはユーザー次第です
* 返されたデータを処理します。エラーが発生した場合は false になります
* $this->error が適切に設定されて返されます。
*
* rfc 821 を実装: HELP [
*
* SMTP コード成功: 211,214
* SMTP コード エラー : 500,501,502,504,421
* @アクセス公開
* @戻り文字列
*/
関数ヘルプ($keyword="") {
$this->error = null; #混乱を避けるため
$this->error = array(
「エラー」=> "接続せずに Help() を呼び出しました");
false を返します;
}
if(!empty($keyword)) {
$extra = " " 。 $キーワード;
}
$code = substr($rply,0,3);
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => "HELP がサーバーから受け付けられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
}
*
で指定したメールアドレスからメール取引を開始します
*$から。成功した場合は true を返し、そうでない場合は false を返します。本当なら
* メールトランザクションが開始され、その後 1 人以上の受信者
* コマンドは、データ コマンドに続いて呼び出すことができます。
*
* rfc 821: MAIL
*
* SMTP コード成功: 250
* SMTP コード成功: 552,451,452
* SMTP コード成功: 500,501,421
* @アクセス公開
* @return bool
*/
関数 Mail($from) {
$this->error = null; #混乱が起こらないように
$this->error = array(
「エラー」=> "接続されていないのに Mail() が呼び出されました");
false を返します;
}
fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $this->CRLF);
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => "メールがサーバーから受け付けられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
true を返します;
}
* コマンド NOOP を SMTP サーバーに送信します。
*
* rfc 821 からの実装: NOOP
*
* SMTP コード成功: 250
* SMTP コード エラー : 500、421
* @アクセス公開
* @return bool
*/
関数 Noop() {
$this->error = null; #混乱が起こらないように
$this->error = array(
「エラー」=> "接続せずに Noop() を呼び出した");
false を返します;
}
$code = substr($rply,0,3);
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => "NOOP がサーバーから受け付けられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
true を返します;
}
* quitコマンドをサーバーに送信し、ソケットを閉じます
* エラーがない場合、または $close_on_error 引数が true の場合。
*
* rfc 821 からの実装: QUIT
*
* SMTP コード成功: 221
* SMTP コード エラー : 500
* @アクセス公開
* @return bool
*/
関数 Quit($close_on_error=true) {
$this->error = null; #混乱しないように
$this->error = array(
「エラー」=> "接続せずに Quit() を呼び出した");
false を返します;
}
fputs($this->smtp_conn,"終了" . $this->CRLF);
$byemsg = $this->get_lines();
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $byemsg;
}
$e = null;
if($code != 221) {
# e を一時変数として使用すると、閉じると $this->error
が上書きされます
$e = array("error" => "SMTP サーバーが終了コマンドを拒否しました",
"smtp_code" => $コード、
"smtp_rply" => substr($byemsg,4));
$rval = false;
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $e["エラー"] 。 ": " .
$byemsg 。 $this->CRLF;
}
}
$this->Close();
}
}
* $to の TO: 引数を使用してコマンド RCPT を SMTP サーバーに送信します
* 受信者が受け入れられた場合は true を返し、拒否された場合は false を返します。
*
* rfc 821 からの実装: RCPT
*
* SMTP コード成功: 250,251
* SMTP コードのエラー: 550,551,552,553,450,451,452
* SMTP コード エラー : 500,501,503,421
* @アクセス公開
* @return bool
*/
関数受信者($to) {
$this->error = null; #混乱が起こらないように
$this->error = array(
「エラー」=> "接続されていないのに Recipient() が呼び出されました");
false を返します;
}
$code = substr($rply,0,3);
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => "RCPT がサーバーから受け入れられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
true を返します;
}
* RSETコマンドを送信してトランザクションを中止します
※現在進行中です。成功した場合は true を返します false
*そうでない場合は
*
* rfc 821: RSET
*
* SMTP コード成功: 250
* SMTP コード エラー : 500,501,504,421
* @アクセス公開
* @return bool
*/
関数 Reset() {
$this->error = null; #混乱が起こらないように
$this->error = array(
「エラー」=> "接続せずに Reset() を呼び出した");
false を返します;
}
$code = substr($rply,0,3);
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => "RSET が失敗しました",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
}
*
で指定したメールアドレスからメール取引を開始します
*$から。成功した場合は true を返し、そうでない場合は false を返します。本当なら
* メールトランザクションが開始され、その後 1 人以上の受信者
* コマンドの後にデータ コマンドを呼び出すことができます。このコマンド
* ユーザーがログインしている場合、ユーザーの端末にメッセージを送信します
*で
*
* rfc 821 を実装: SEND
*
* SMTP コード成功: 250
* SMTP コード成功: 552,451,452
* SMTP コード成功: 500,501,502,421
* @アクセス公開
* @return bool
*/
関数 Send($from) {
$this->error = null; #混乱が起こらないように
$this->error = array(
「エラー」=> "接続されていないのに Send() が呼び出されました");
false を返します;
}
$code = substr($rply,0,3);
echo "SMTP -> FROM SERVER:" 。 $this->CRLF 。 $rply;
}
$this->エラー=
array("error" => "サーバーからの SEND が受け付けられませんでした",
"smtp_code" => $コード、
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> エラー: " 。 $this->error["error"] .
":" 。 $rply 。 $this->CRLF;
}
false を返します;
}
true を返します;
}
*
で指定したメールアドレスからメール取引を開始します
*$から。成功した場合は true を返し、そうでない場合は false を返します。本当なら
* メールトランザクションが開始され、その後 1 人以上の受信者
* コマンドの後にデータ コマンドを呼び出すことができます。このコマンド
* ユーザーがログインしている場合、ユーザーの端末にメッセージを送信します
* に入力してメールを送信してください。
*
* rfc 821: SAML
*
* SMTP コード成功: 250
* SMTP コード成功: 552,451,452
* SMTP コード成功: 500,501,502,421
* @アクセス公開
* @return bool
&nbs