ソケット プログラミングの概要
私は TCP/IP プログラミングの専門家ではないので、ここでは私の理解と経験を共有しているだけであることを皆さんにお伝えしたいと思います。
fsockopen 関数を使用してインターネット接続を開きます。関数の構文形式は次のとおりです:
int fsockopen(string hostname, int port, int [errno], string [errstr], int [timeout]);
I don'tパラメータの意味を説明する必要はないと思います。はい、ここでは SMTP プロトコルが使用されているため、ポート番号は 25 です。接続が正常に開かれると、ファイル ハンドルのように使用できるソケット ハンドルが返されます。利用可能な操作には、fputs()、fgets()、feof()、fclose()
などが含まれます。
TCP/IPをベースとしたインターネットプロトコルの一般的なコマンド形式は、リクエスト/レスポンス方式で実装されており、すべてテキスト情報が使用されるため、
の処理が容易です。 SMTP は Simple Mail Transfer Protocol の略称で、クライアントがサーバーに電子メールを送信できるようにします。したがって、
以下で説明するコマンドは、クライアントがサーバーにリクエスト命令を送信することを指し、応答はサーバーからクライアントに返される情報を指します。
の本文部分であり、最後の終了行は終了行として独立した「.」である必要があります。
クライアントでよく使用される SMTP コマンドは次のとおりです:
HELO ホスト名: サーバーに挨拶し、使用されるマシン名をクライアントに通知します。気軽に入力できます。
RCPT TO:receiver_id:tell サーバーの受信者のアドレス
DATA:レターの内容は以下で送信を開始し、 のみを含む特別な行で終わる必要がありますRESET:前のコマンドをキャンセルして最初からやり直します。
VERIFY userid: アカウントが存在するかどうかを確認します (このコマンドはオプションです)。サーバーがサポートしていない可能性があります)
QUIT: 接続を終了し、終了します
サーバーから返される応答情報は次のとおりです (形式は次のとおりです: 応答コード + スペース+ 説明):
220 サービス準備完了 (ソケット接続が成功するとこの情報が返されます)
221 処理中です
250 リクエスト電子メールアクションは正しく完了しています (この情報は、HELO、MAIL FROM、 RCPT TO、QUIT コマンドが正常に実行されました)
500 構文エラー、コマンドが認識できません
550コマンドを実行できません。電子メールが無効です
552 割り込み処理: ユーザーがファイル容量を超えています
簡単なコマンドヘッダーを以下に示します (これはソケットを開いた後に行われます)。これは、stmp に電子メールを送信したテスト結果です。 263.net:
HELO limodou
250 smtp.263.net
MAIL FROM: chatme@263.net
RCPT TO: chatme@263.net
250 OK
データ
354 データは
で終了します。これSMTP についての簡単な知識です。関連コンテンツは RFC にあります。
RFC 821 では、電子メールの送受信に関連するコマンドが定義されています。
RFC 822 は電子メールを規定していますか?
RFC 2045-2048 はマルチメディア電子メールを規定していますか?
RFC 1113、1422-1424 は電子メールの機密性を向上させる方法について説明しています。
send_mailクラスの実装
今回は私が作成したsend mailクラスを紹介します。上記の準備知識を踏まえて、以下のように実装していきます。
クラスのメンバー変数
var $lastmessage; //返された最後の応答メッセージを記録します
var $lastact; //ユーザーを歓迎するために HELO の背後で使用されますvar $debug; //デバッグ情報を表示するかどうか
var $smtp; //smtp サーバー
var $port; //smtp ポート番号
var $fp; このうち $lastmessage と $lastact を使用します最後の A 応答メッセージと実行されたコマンドを記録し、エラーが発生したときにユーザーが使用できるようにします
クラスの構築
------------------------------------------------ --------------------------------
関数 send_mail($smtp, $welcome="", $debug=false)
{
if(empty($smtp)) die("SMTP を NULL にすることはできません!");
$this->smtp=$smtp;
if(empty($welcome))
$this-> welcome=gethostbyaddr("localhost");
else
$this->debug=$debug;
$this- >lastact="";
$this->port="25";
-------------- -------------------------------------------------- --
このコンストラクターは主にいくつかの初期値の決定と設定を完了します。 $welcome は、サーバーにユーザーの名前を伝えるために HELO ディレクティブで使用されます。
HELO コマンドにはマシン名が必要ですが、マシン名なしで使用できます。ユーザーが $welcome を指定しない場合、ローカル マシン名が自動的に検索されます。
デバッグ情報を表示
------------------------------------------ ----- -------------------------------------
1 関数 show_debug($message, $inout)
3 if ($this->debug)
4 {5 if($inout=="in") //応答情報
6 {
7 $m='<< ;
8 }
9 else
10 $m='>>
11 if(!ereg("n$", $message))
12 $message .= "
"; $message=nl2br( $message);
14 echo "${m}${message}"; ----- -------------------------------------- ----- ------------------
この関数はデバッグ情報を表示するために使用されます。 $inout には、アップロード命令であるか返される応答であるかを指定できます。アップロード命令である場合は "out" を使用し、返される応答である場合は "in" を使用します。
3行目はデバッグ情報を出力するかどうかを決定します。
5 行目で、応答メッセージであるかどうかを判断し、そうでない場合は 7 行目の情報の前に「>>」を追加します。それをアップロードします。
11 ~ 12 行目、情報文字列の最後の行が改行文字であるかどうかを判断し、そうでない場合は HTML 改行マークを追加します。 13 行目は、すべての改行文字を HTML
改行タグに変換します。
14 行目、メッセージ全体を出力し、違いを示すためにメッセージの色をグレーに設定します。
コマンドを実行
1 関数 do_command($command , $code)
2 {
3 $this->lalastact=$command;
4 $this->show_debug($this->lastact, "out");
5 fputs ( $this->fp , $this->lafact );
6 $this->lastmessage = fgets ( $this->fp, 512 );
8 if( !ereg("^$code", $this->lastmessage))
9 {10 return false;
12 else
14 }
----- ----- -------------------------------------- ----- --------------------
ソケット処理部分を書いているときに、HELO、MAIL などのいくつかのコマンドの処理が非常に似ていることがわかりました。 FROM、RCPT TO、QUIT、DATA コマンド
は両方とも、デバッグ情報が表示されるかどうかに基づいて、関連するコンテンツを表示する必要があります。同時に、返された応答コードが予期されている場合は、処理を続行する必要があります。予期しない場合は、処理を中断する必要があります。したがって、明確化および単純化のために、これらのコマンドを処理するために一般的な処理関数が特別に作成されます。関数のパラメーターの
$code は、期待される応答コードです。応答コードが同じであれば、処理は成功したことを意味します。それ以外の場合は、エラーが発生します。
行 3 は、最後に実行されたコマンドを記録します。
4 行目はアップロード コマンドを表示します。
5行目はfputsを使用して命令を実際にサーバーに転送します。
6行目、サーバーから受信した応答情報は最後の応答メッセージ変数に格納されます。
7行目は応答情報を表示します。
8 行目は、応答情報が期待されているかどうかを判断し、期待されている場合は 13 行目で成功 (true) を返し、それ以外の場合は 10 行目で失敗 (false) を返します。
このようにして、この関数は、一方では指示や情報を送信して表示する機能を完了し、他方では返された応答が成功したかどうかを判断します。
メール送信処理
以下が本当の秘密ですが、よく見てください。 :)
------------------------------------------------- -------------------------------
1 関数 send($to,$from,$subject,$message)
2 {
3
4 //接服务器
5 $this->lastact="connect";
6
7 $this->show_debug("SMTP サーバーに接続します : ".$this->smtp, "out");
8 $this->fp = fsockopen ( $this->smtp, $this->port );
9 if ( $this->fp )
10 {
11
12 set_socket_blocking( $this->fp, true );
13 $this->lastmessage=fgets($this->fp,512);
14 $this->show_debug($this->lastmessage, "in");
15
16 if (! ereg ( "^220", $this->lastmessage ) )
17 {
18 return false;
19 }
20 else
21 {
22 $this->lastact="HELO " . $this->ようこそ。 「ん」;
23 if(!$this->do_command($this->lastact, "250"))
24 {
25 fclose($this->fp);
26 false を返します。
27 }
28
29 $this->lastact="MAIL FROM: $from" 。 「ん」;
30 if(!$this->do_command($this->lastact, "250"))
31 {
32 fclose($this->fp);
33 false を返します。
34 }
35
36 $this->lastact="RCPT TO: $to" 。 「ん」;
37 if(!$this->do_command($this->lastact, "250"))
38 {
39 fclose($this->fp);
40 false を返します。
41 }
42
43 //送信正文
44 $this->lastact="DATAn";
45 if(!$this->do_command($this->lastact, "354"))
46 {
47 fclose($this->fp);
48 false を返します。
49 }
50
51 //处理Subject头
52 $head="Subject: $subjectn";
53 if(!empty($subject) && !ereg($head, $message))
54 {
55 $message = $head.$message;
56 }
57
58 //处理From头
59 $head="From: $fromn";
60 if(!empty($from) && !ereg($head, $message))
61 {
62 $message = $head.$message;
63 }
64
65 //处理To头
66 $head="To: $ton";
67 if(!empty($to) && !ereg($head, $message))
68 {
69 $message = $head.$message;
70 }
71
72 //加上结束串
73 if(!ereg("n.n", $message))
74 $message .= "n.n";
75 $this->show_debug($message, "out");
76 fputs($this->fp, $message);
77
78 $this->lastact="QUITn";
79 if(!$this->do_command($this->lastact, "250"))
80 {
81 fclose($this->fp);
82 false を返します。
83 }
84 }
85 true を返します。
86 }
87 else
88 {
89 $this->show_debug("接続に失敗しました!", "in");
90 false を返します。
91 }
92 }
------------------------------------------ -------------------------------------
いくつかの意思決定は明確な我就不说了。
処理が成功した場合は true を返し、失敗した場合は false を返します。
8 行目、メールサーバーに接続します。成功した場合、応答コードは 220 になります。
12 行目はブロック モードを設定し、続行する前に情報を返す必要があることを示します。詳細な手順についてはマニュアルを参照してください。
16 行目、応答コードが 220 であるかどうかを判断し、220 である場合は処理を続行します。それ以外の場合はエラーが返されます。
22 ~ 27 行目、HELO 命令の処理、予期される応答コードは 250 です。
29 ~ 34 行目、MAIL FROM 命令の処理、予期される応答コードは 250 です。
行 36 ~ 41、RCPT TO 命令の処理、予期される応答コードは 250 です。
44 ~ 49 行目、DATA コマンドの処理、予期される応答コードは 354 です。
51 ~ 76 行目、メール本文を生成して送信します。
52~56行目は、$subjectが空でない場合、メール本文に件名部分があるかどうかを確認し、ない場合は件名部分を追加します。
59〜63行目、$fromが空でない場合、メール本文に送信者部分があるかどうかを確認し、存在しない場合は送信者部分を追加します。
66〜70行目、$toが空でない場合、メール本文に受信者部分があるかどうかを確認し、存在しない場合は受信者部分を追加します。
73~74行目、メール本文に終了行があるかどうかを確認し、ない場合はメール本文の終了行(特殊行として「.」を別行として追加)を追加します。
76行目、メール本文を送信します。
78 ~ 83 行目、QUIT を実行してサーバーとの接続を終了します。予期される応答コードは 250 です。
85行目、処理成功フラグ(true)を返します。
81~91行目、サーバーへの接続失敗の処理。
上記は send_mail クラス全体の実装であり、難しいことではありません。以下に例を示します。
メール送信例
まずは最も簡単な例を見てみましょう:
--------------------------------- -- ------------------------------------------------
< ;?
1 include "sendmail.class.php3";
2 $email="こんにちは、これはテストレターです!"
3 $sendmail=new send_mail("smtp.263.net", "limodou", true) ); //調整情報を表示
4 if($sendmail->send("chatme@263.net", "chatme@263.net", "test", $email))
5 {
6 echo "送信に成功しました !
";
7 }
8 else
9 {
10 echo "送信に失敗しました!
";
11 }
?>
---------- ---------------------------------------------------- --------------- ------------------
1 行目、send_mail クラスをロードします。
3行目、クラスのインスタンスを作成し、表示したくない場合は、
$sendmail=new send_mail("smtp.263.net"); と設定します。
4 行目、メールを送信します。
シンプルですね。次に、前の MIME 電子メールの送信例に基づいて、HTML 添付ファイルを送信する例を示します。
------------------------------------------------ --------------------------------
"MIME.class.php3"; /注、MIME メールの送信に関する記事では、このクラス ファイルの名前は MIME.class です。ここでは、次のように変更しました
$ str = "ニュースレター for ".date('MY', time());
$html_data = '
//コメントアウトしてメール送信処理を使用します
//メールを生成します
//メールを表示します情報
//sendmail ファイルをインクルード
// インスタンスを作成
//メールを送信
?>