分享
 
 
 

用PHP實現POP3郵件的收取(二)

王朝php·作者佚名  2008-12-23
窄屏简体版  字體: |||超大  

用PHP實現POP3收取郵件的類

現在讓我們來用PHP實現一個通過POP3協議收取信件的類吧,這個類中所用到的一些sock操作的函數,不另做特殊說明,請參考php的有關資料。通過這個實例,相信你也會和我一樣,感覺到PHP中對於sock操作的靈活、方便和功能的強大。

首先,我們來說明一下這個類中需要用到的一些內部成員變量:(這些變量應該都是對外封閉的,可是由於php對類的成員變量沒有private與publice之類的分別,只好就這麽直接定義了。這是PHP的一個令人遺憾的地方。)

1.成員變量說明

class pop3

{

var $hostname=""; // POP主機名

var $port=110; // 主機的POP3端口,一般是110號端口

var $timeout=5;// 連接主機的最大超時時間

var $connection=0; // 保存與主機的連接

var $state="DISCONNECTED"; // 保存當前的狀態

var $debug=0;// 做為標識,是否在調試狀態,是的話,輸出調試信息

var $err_str='';// 如果出錯,這裏保存錯誤信息

var $err_no;//如果出錯,這裏保存錯誤號碼

var $resp; // 臨時保存服務器的響應信息

var $apop; // 指示需要使用加密方式進行密碼驗證,一般服務器不需要

var $messages; //郵件數

var $size; //各郵件的總大小

var $mail_list; // 一個數組,保存各個郵件的大小及其在郵件服務器上序號

var $head=array(); // 郵件頭的內容,數組

var $body=array(); // 郵件體的內容,數組;

2.當然,這其中的有些變量,僅通過這樣一個簡單的說明並不能完全了解如何使用,下面我就逐個來說明這個類實現中的一些主要方法:

Function pop3($server="192.100.100.1",$port=110,$time_out=5)

{$this->hostname=$server;

$this->port=$port;

$this->timeout=$time_out;

return true;

}

熟悉面向對象編程的朋友一看就會知道,這是這個類的構造函數,在初始化這個類時,可以給出這幾個最基本的參數:pop3服務器的地址,端口號,及連接服務器時的最大超時時間。一般來說,只需要給出POP3服務器的地址就行了。

Function open()

{

if($this->hostname=="")

{$this->err_str="無效的主機名!!";

return false;

}

if ($this->debug) echo "正在打開$this->hostname,$this->port,&$err_no, &$err_str, $this->timeout<BR>";

if (!$this->connection=fsockopen($this->hostname,$this->port,&$err_no, &$err_str, $this->timeout))

{

$this->err_str="連接到POP服務器失敗,錯誤信息:".$err_str."錯誤號:".$err_no;

return false;

}

else

{

$this->getresp();

if($this->debug)

$this->outdebug($this->resp);

if (substr($this->resp,0,3)!="+OK")

{$this->err_str="服務器返回無效的信息:".$this->resp."請檢查POP服務器是否正確";

return false;

}

$this->state="AUTHORIZATION";

return true;

}

}

該方法不需要任何參數就可建立與POP3服務器的sock連接。該方法又用到了另一個類中的方法$this->getresp();下面是這個方法的聲明:

Function getresp()

{

for($this->resp="";;)

{

if(feof($this->connection))

return false;

$this->resp.=fgets($this->connection,100);

$length=strlen($this->resp);

if($length>=2 && substr($this->resp,$length-2,2)=="\r\n")

{

$this->resp=strtok($this->resp,"\r\n");

return true;

}

}

}

這個方法取得服務器端的返回信息並進行簡單的處理:去掉最後的回車換行符,將返回信息保存在resp這個內部變量中。這個方法在後面的多個操作中都將用到。另外,還有個小方法也在後面的多個操作中用到:

Function outdebug($message)

{

echo htmlspecialchars($message)."<br>\n";

}

它的作用就是把調試信息$message顯示出來,並把一些特殊字符進行轉換以及在行尾加上<br>標簽,這樣是為了使其輸出的調試信息便於閱讀和分析。

建立起與服務器的sock連接之後,就要給服務器發送相關的命令了(請參見上面的與服務器對話的過程)從上面對POP對話的分析可以看到,每次都是發送一條命令,然後服務器給予一定的回應,如果命令的執行是對的,回應一般是以+OK開頭,後面是一些描述信息,所以,我們可以做一個通過發送命令的方法:

Function command($command,$return_lenth=1,$return_code='+')

{

if ($this->connection==0)

{

$this->err_str="沒有連接到任何服務器,請檢查網絡連接";

return false;

}

if ($this->debug)

$this->outdebug(">>> $command");

if (!fputs($this->connection,"$command\r\n"))

{

$this->err_str="無法發送命令".$command;

return false;

}

else

{

$this->getresp();

if($this->debug)

$this->outdebug($this->resp);

if (substr($this->resp,0,$return_lenth)!=$return_code)

{

$this->err_str=$command." 命令服務器返回無效:".$this->resp;

return false;

}

else

return true;

}

}

這個方法可以接受三個參數: $command--> 發送給服務器的命令; $return_lenth,$return_code ,指定從服務器的返回中取多長的值做為命令返回的標識以及這個標識的正確值是什麽。對於一般的pop操作來說,如果服務器的返回第一個字符為"+",則可以認為命令是正確執行了。也可以用前面提到過的三個字符"+OK"做為判斷的標識。

下面介紹的幾個方法則可以按照前述收取信件的對話去理解,因為有關的內容已經在前面做了說明,因此下面的方法不做詳細的說明,請參考其中的註釋:

Function Login($user,$password)//發送用戶名及密碼,登錄到服務器

{

if($this->state!="AUTHORIZATION")

{

$this->err_str="還沒有連接到服務器或狀態不對";

return false;

}

if (!$this->apop) //服務器是否采用APOP用戶認證

{

if (!$this->command("USER $user",3,"+OK")) return false;

if (!$this->command("PASS $password",3,"+OK")) return false;

}

else

{

//echo $this->resp=strtok($this->resp,"\r\n");

if (!$this->command("APOP $user ".md5($this->greeting.$password),3,"+OK")) return false;

}

$this->state="TRANSACTION"; // 用戶認證通過,進入傳送模式

return true;

}

Function stat() // 對應著stat命令,取得總的郵件數與總的大小

{

if($this->state!="TRANSACTION")

{

$this->err_str="還沒有連接到服務器或沒有成功登錄";

return false;

}

if (!$this->command("STAT",3,"+OK"))

return false;

else

{

$this->resp=strtok($this->resp," ");

$this->messages=strtok(" "); // 取得郵件總數

$this->size=strtok(" "); //取得總的字節大小

return true;

}

}

Function listmail($mess=null,$uni_id=null) //對應的是LIST命令,取得每個郵件的大小及序號。一般來說用到的是List命令,如果指定了$uni_id ,則使用UIDL命令,返回的是每個郵件的標識符,事實上,這個標識符一般是沒有什麽用的。取得的各個郵件的大小返回到類的內部變量mail_list這個二維數組裏。

{

if($this->state!="TRANSACTION")

{

$this->err_str="還沒有連接到服務器或沒有成功登錄";

return false;

}

if ($uni_id)

$command="UIDL ";

else

$command="LIST ";

if ($mess)

$command.=$mess;

if (!$this->command($command,3,"+OK"))

{

//echo $this->err_str;

return false;

}

else

{

$i=0;

$this->mail_list=array();

$this->getresp();

while ($this->resp!=".")

{ $i++;

if ($this->debug)

{

$this->outdebug($this->resp);

}

if ($uni_id)

{

$this->mail_list[$i][num]=strtok($this->resp," ");

$this->mail_list[$i][size]=strtok(" ");

}

else

{

$this->mail_list[$i]["num"]=intval(strtok($this->resp," "));

$this->mail_list[$i]["size"]=intval(strtok(" "));

}

$this->getresp();

}

return true;

}

}

function getmail($num=1,$line=-1)// 取得郵件的內容,$num是郵件的序號,$line是指定共取得正文的多少行。有些時候,如郵件比較大而我們只想先查看郵件的主題時是必須指定行數的。默認值$line=-1,即取回所有的郵件內容,取得的內容存放到內部變量$head,$body兩個數組裏,數組裏的每一個元素對應的是郵件源代碼的一行。

{

if($this->state!="TRANSACTION")

{

$this->err_str="不能收取信件,還沒有連接到服務器或沒有成功登錄";

return false;

}

if ($line<0)

$command="RETR $num";

else

$command="TOP $num $line";

if (!$this->command("$command",3,"+OK"))

return false;

else

{

$this->getresp();

$is_head=true;

while ($this->resp!=".") // . 號是郵件結束的標識

{

if ($this->debug)

$this->outdebug($this->resp);

if (substr($this->resp,0,1)==".")

$this->resp=substr($this->resp,1,strlen($this->resp)-1);

if (trim($this->resp)=="") // 郵件頭與正文部分的是一個空行

$is_head=false;

if ($is_head)

$this->head[]=$this->resp;

else

$this->body[]=$this->resp;

$this->getresp();

}

return true;

}

} // end function

function dele($num) // 刪除指定序號的郵件,$num 是服務器上的郵件序號

{

if($this->state!="TRANSACTION")

{

$this->err_str="不能刪除遠程信件,還沒有連接到服務器或沒有成功登錄";

return false;

}

if (!$num)

{

$this->err_str="刪除的參數不對";

return false;

}

if ($this->command("DELE $num ",3,"+OK"))

return true;

else

return false;

}

通過以上幾個方法,我們已經可以實現郵件的查看、收取、刪除的操作,不過別忘了最後要退出,並關閉與服務器的連接,調用下面的這個方法:

Function Close()

{

if($this->connection!=0)

{

if($this->state=="TRANSACTION")

$this->command("QUIT",3,"+OK");

fclose($this->connection);

$this->connection=0;

$this->state="DISCONNECTED";

}

}

 
 
 
免責聲明:本文為網絡用戶發布,其觀點僅代表作者個人觀點,與本站無關,本站僅提供信息存儲服務。文中陳述內容未經本站證實,其真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,並請自行核實相關內容。
2023年上半年GDP全球前十五強
 百态   2023-10-24
美眾議院議長啟動對拜登的彈劾調查
 百态   2023-09-13
上海、濟南、武漢等多地出現不明墜落物
 探索   2023-09-06
印度或要將國名改為「巴拉特」
 百态   2023-09-06
男子為女友送行,買票不登機被捕
 百态   2023-08-20
手機地震預警功能怎麽開?
 干货   2023-08-06
女子4年賣2套房花700多萬做美容:不但沒變美臉,面部還出現變形
 百态   2023-08-04
住戶一樓被水淹 還衝來8頭豬
 百态   2023-07-31
女子體內爬出大量瓜子狀活蟲
 百态   2023-07-25
地球連續35年收到神秘規律性信號,網友:不要回答!
 探索   2023-07-21
全球鎵價格本周大漲27%
 探索   2023-07-09
錢都流向了那些不缺錢的人,苦都留給了能吃苦的人
 探索   2023-07-02
倩女手遊刀客魅者強控制(強混亂強眩暈強睡眠)和對應控制抗性的關系
 百态   2020-08-20
美國5月9日最新疫情:美國確診人數突破131萬
 百态   2020-05-09
荷蘭政府宣布將集體辭職
 干货   2020-04-30
倩女幽魂手遊師徒任務情義春秋猜成語答案逍遙觀:鵬程萬裏
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案神機營:射石飲羽
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案昆侖山:拔刀相助
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案天工閣:鬼斧神工
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案絲路古道:單槍匹馬
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案鎮郊荒野:與虎謀皮
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案鎮郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案鎮郊荒野:指鹿為馬
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案金陵:小鳥依人
 干货   2019-11-12
倩女幽魂手遊師徒任務情義春秋猜成語答案金陵:千金買鄰
 干货   2019-11-12
 
>>返回首頁<<
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有