用PHP實(shí)現(xiàn)POP3郵件的收?。ǘ?/h1>
瀏覽:2日期:2023-12-28 10:15:43
用PHP實(shí)現(xiàn)POP3收取郵件的類
現(xiàn)在讓我們來(lái)用PHP實(shí)現(xiàn)一個(gè)通過(guò)POP3協(xié)議收取信件的類吧,這個(gè)類中所用到的一些sock操作的函數(shù),不另做特殊說(shuō)明,請(qǐng)參考php的有關(guān)資料。通過(guò)這個(gè)實(shí)例,相信你也會(huì)和我一樣,感覺到PHP中對(duì)于sock操作的靈活、方便和功能的強(qiáng)大。
首先,我們來(lái)說(shuō)明一下這個(gè)類中需要用到的一些內(nèi)部成員變量:(這些變量應(yīng)該都是對(duì)外封閉的,可是由于php對(duì)類的成員變量沒有private與publice之類的分別,只好就這么直接定義了。這是PHP的一個(gè)令人遺憾的地方。)
1.成員變量說(shuō)明
class pop3{
var $hostname=''; // POP主機(jī)名
var $port=110; // 主機(jī)的POP3端口,一般是110號(hào)端口
var $timeout=5;// 連接主機(jī)的最大超時(shí)時(shí)間
var $connection=0; // 保存與主機(jī)的連接
var $state='DISCONNECTED'; // 保存當(dāng)前的狀態(tài)
var $debug=0;// 做為標(biāo)識(shí),是否在調(diào)試狀態(tài),是的話,輸出調(diào)試信息
var $err_str='';// 如果出錯(cuò),這里保存錯(cuò)誤信息
var $err_no; //如果出錯(cuò),這里保存錯(cuò)誤號(hào)碼
var $resp; // 臨時(shí)保存服務(wù)器的響應(yīng)信息
var $apop; // 指示需要使用加密方式進(jìn)行密碼驗(yàn)證,一般服務(wù)器不需要
var $messages; // 郵件數(shù)
var $size; //各郵件的總大小
var $mail_list; // 一個(gè)數(shù)組,保存各個(gè)郵件的大小及其在郵件服務(wù)器上序號(hào)
var $head=array(); // 郵件頭的內(nèi)容,數(shù)組
var $body=array(); // 郵件體的內(nèi)容,數(shù)組;
2.當(dāng)然,這其中的有些變量,僅通過(guò)這樣一個(gè)簡(jiǎn)單的說(shuō)明并不能完全了解如何使用,下面我就逐個(gè)來(lái)說(shuō)明這個(gè)類實(shí)現(xiàn)中的一些主要方法:Function pop3($server='192.100.100.1',$port=110,$time_out=5)
{$this->hostname=$server;
$this->port=$port;
$this->timeout=$time_out;
return true;}
熟悉面向?qū)ο缶幊痰呐笥岩豢淳蜁?huì)知道,這是這個(gè)類的構(gòu)造函數(shù),在初始化這個(gè)類時(shí),可以給出這幾個(gè)最基本的參數(shù):pop3服務(wù)器的地址,端口號(hào),及連接服務(wù)器時(shí)的最大超時(shí)時(shí)間。一般來(lái)說(shuō),只需要給出POP3服務(wù)器的地址就行了。
Function open(){if($this->hostname=='')
{$this->err_str='無(wú)效的主機(jī)名!!';
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服務(wù)器失敗,錯(cuò)誤信息:'.$err_str.'錯(cuò)誤號(hào):'.$err_no;
return false;
} else { $this->getresp();
if($this->debug)
$this->outdebug($this->resp);
if (substr($this->resp,0,3)!='+OK')
{$this->err_str='服務(wù)器返回?zé)o效的信息:'.$this->resp.'請(qǐng)檢查POP服務(wù)器是否正確';
return false; }
$this->state='AUTHORIZATION';
return true;
}
}
該方法不需要任何參數(shù)就可建立與POP3服務(wù)器的sock連接。該方法又用到了另一個(gè)類中的方法$this->getresp();下面是這個(gè)方法的聲明:
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)=='rn')
{
$this->resp=strtok($this->resp,'rn');
return true;
}}}
這個(gè)方法取得服務(wù)器端的返回信息并進(jìn)行簡(jiǎn)單的處理:去掉最后的回車換行符,將返回信息保存在resp這個(gè)內(nèi)部變量中。這個(gè)方法在后面的多個(gè)操作中都將用到。另外,還有個(gè)小方法也在后面的多個(gè)操作中用到:
Function outdebug($message){ echo htmlspecialchars($message).'<br>n';}
它的作用就是把調(diào)試信息$message顯示出來(lái),并把一些特殊字符進(jìn)行轉(zhuǎn)換以及在行尾加上<br>標(biāo)簽,這樣是為了使其輸出的調(diào)試信息便于閱讀和分析。
建立起與服務(wù)器的sock連接之后,就要給服務(wù)器發(fā)送相關(guān)的命令了(請(qǐng)參見上面的與服務(wù)器對(duì)話的過(guò)程)從上面對(duì) POP對(duì)話的分析可以看到,每次都是發(fā)送一條命令,然后服務(wù)器給予一定的回應(yīng),如果命令的執(zhí)行是對(duì)的,回應(yīng)一般是以+OK開頭,后面是一些描述信息,所以,我們可以做一個(gè)通過(guò)發(fā)送命令的方法:
Function command($command,$return_lenth=1,$return_code='+'){ if ($this->connection==0) { $this->err_str='沒有連接到任何服務(wù)器,請(qǐng)檢查網(wǎng)絡(luò)連接';
return false; }
if ($this->debug) $this->outdebug('>>> $command');
if (!fputs($this->connection,'$commandrn'))
{
$this->err_str='無(wú)法發(fā)送命令'.$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.' 命令服務(wù)器返回?zé)o效:'.$this->resp;
return false;
}
else
return true;
}}
這個(gè)方法可以接受三個(gè)參數(shù): $command--> 發(fā)送給服務(wù)器的命令; $return_lenth,$return_code ,指定從服務(wù)器的返回中取多長(zhǎng)的值做為命令返回的標(biāo)識(shí)以及這個(gè)標(biāo)識(shí)的正確值是什么。對(duì)于一般的pop操作來(lái)說(shuō),如果服務(wù)器的返回第一個(gè)字符為'+',則可以認(rèn)為命令是正確執(zhí)行了。也可以用前面提到過(guò)的三個(gè)字符'+OK'做為判斷的標(biāo)識(shí)。
下面介紹的幾個(gè)方法則可以按照前述收取信件的對(duì)話去理解,因?yàn)橛嘘P(guān)的內(nèi)容已經(jīng)在前面做了說(shuō)明,因此下面的方法不做詳細(xì)的說(shuō)明,請(qǐng)參考其中的注釋:
Function Login($user,$password) //發(fā)送用戶名及密碼,登錄到服務(wù)器{
if($this->state!='AUTHORIZATION') {
$this->err_str='還沒有連接到服務(wù)器或狀態(tài)不對(duì)';
return false; }
if (!$this->apop) //服務(wù)器是否采用APOP用戶認(rèn)證 {
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,'rn');
if (!$this->command('APOP $user '.md5($this->greeting.$password),3,'+OK')) return false;
}
$this->state='TRANSACTION'; // 用戶認(rèn)證通過(guò),進(jìn)入傳送模式
return true;}
Function stat() // 對(duì)應(yīng)著stat命令,取得總的郵件數(shù)與總的大小{if($this->state!='TRANSACTION') {
$this->err_str='還沒有連接到服務(wù)器或沒有成功登錄';
return false; }
if (!$this->command('STAT',3,'+OK')) return false;
else
{
$this->resp=strtok($this->resp,' ');
$this->messages=strtok(' '); // 取得郵件總數(shù)
$this->size=strtok(' '); //取得總的字節(jié)大小
return true; }}
Function listmail($mess=null,$uni_id=null) //對(duì)應(yīng)的是LIST命令,取得每個(gè)郵件的大小及序號(hào)。一般來(lái)說(shuō)用到的是List命令,如果指定了$uni_id ,則使用UIDL命令,返回的是每個(gè)郵件的標(biāo)識(shí)符,事實(shí)上,這個(gè)標(biāo)識(shí)符一般是沒有什么用的。取得的各個(gè)郵件的大小返回到類的內(nèi)部變量mail_list這個(gè)二維數(shù)組里。
{if($this->state!='TRANSACTION') {
$this->err_str='還沒有連接到服務(wù)器或沒有成功登錄';
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) // 取得郵件的內(nèi)容,$num是郵件的序號(hào),$line是指定共取得正文的多少行。有些時(shí)候,如郵件比較大而我們只想先查看郵件的主題時(shí)是必須指定行數(shù)的。默認(rèn)值$line=-1,即取回所有的郵件內(nèi)容,取得的內(nèi)容存放到內(nèi)部變量$head,$body兩個(gè)數(shù)組里,數(shù)組里的每一個(gè)元素對(duì)應(yīng)的是郵件源代碼的一行。
{
if($this->state!='TRANSACTION') { $this->err_str='不能收取信件,還沒有連接到服務(wù)器或沒有成功登錄';
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!='.') // . 號(hào)是郵件結(jié)束的標(biāo)識(shí) {
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)=='') // 郵件頭與正文部分的是一個(gè)空行
$is_head=false;
if ($is_head)
$this->head[]=$this->resp;
else
$this->body[]=$this->resp;
$this->getresp();
}
return true; } } // end function
function dele($num) // 刪除指定序號(hào)的郵件,$num 是服務(wù)器上的郵件序號(hào)
{
if($this->state!='TRANSACTION') {
$this->err_str='不能刪除遠(yuǎn)程信件,還沒有連接到服務(wù)器或沒有成功登錄';
return false; }
if (!$num) {
$this->err_str='刪除的參數(shù)不對(duì)';
return false; }
if ($this->command('DELE $num ',3,'+OK')) return true;
else
return false;}
通過(guò)以上幾個(gè)方法,我們已經(jīng)可以實(shí)現(xiàn)郵件的查看、收取、刪除的操作,不過(guò)別忘了最后要退出,并關(guān)閉與服務(wù)器的連接,調(diào)用下面的這個(gè)方法:
Function Close(){
if($this->connection!=0) {
if($this->state=='TRANSACTION')
$this->command('QUIT',3,'+OK');
fclose($this->connection);
$this->connection=0;
$this->state='DISCONNECTED'; }
}
標(biāo)簽:
PHP
上一條:下一條:
用PHP實(shí)現(xiàn)POP3收取郵件的類
現(xiàn)在讓我們來(lái)用PHP實(shí)現(xiàn)一個(gè)通過(guò)POP3協(xié)議收取信件的類吧,這個(gè)類中所用到的一些sock操作的函數(shù),不另做特殊說(shuō)明,請(qǐng)參考php的有關(guān)資料。通過(guò)這個(gè)實(shí)例,相信你也會(huì)和我一樣,感覺到PHP中對(duì)于sock操作的靈活、方便和功能的強(qiáng)大。
首先,我們來(lái)說(shuō)明一下這個(gè)類中需要用到的一些內(nèi)部成員變量:(這些變量應(yīng)該都是對(duì)外封閉的,可是由于php對(duì)類的成員變量沒有private與publice之類的分別,只好就這么直接定義了。這是PHP的一個(gè)令人遺憾的地方。)
1.成員變量說(shuō)明
class pop3{
var $hostname=''; // POP主機(jī)名
var $port=110; // 主機(jī)的POP3端口,一般是110號(hào)端口
var $timeout=5;// 連接主機(jī)的最大超時(shí)時(shí)間
var $connection=0; // 保存與主機(jī)的連接
var $state='DISCONNECTED'; // 保存當(dāng)前的狀態(tài)
var $debug=0;// 做為標(biāo)識(shí),是否在調(diào)試狀態(tài),是的話,輸出調(diào)試信息
var $err_str='';// 如果出錯(cuò),這里保存錯(cuò)誤信息
var $err_no; //如果出錯(cuò),這里保存錯(cuò)誤號(hào)碼
var $resp; // 臨時(shí)保存服務(wù)器的響應(yīng)信息
var $apop; // 指示需要使用加密方式進(jìn)行密碼驗(yàn)證,一般服務(wù)器不需要
var $messages; // 郵件數(shù)
var $size; //各郵件的總大小
var $mail_list; // 一個(gè)數(shù)組,保存各個(gè)郵件的大小及其在郵件服務(wù)器上序號(hào)
var $head=array(); // 郵件頭的內(nèi)容,數(shù)組
var $body=array(); // 郵件體的內(nèi)容,數(shù)組;
2.當(dāng)然,這其中的有些變量,僅通過(guò)這樣一個(gè)簡(jiǎn)單的說(shuō)明并不能完全了解如何使用,下面我就逐個(gè)來(lái)說(shuō)明這個(gè)類實(shí)現(xiàn)中的一些主要方法:Function pop3($server='192.100.100.1',$port=110,$time_out=5)
{$this->hostname=$server;
$this->port=$port;
$this->timeout=$time_out;
return true;}
熟悉面向?qū)ο缶幊痰呐笥岩豢淳蜁?huì)知道,這是這個(gè)類的構(gòu)造函數(shù),在初始化這個(gè)類時(shí),可以給出這幾個(gè)最基本的參數(shù):pop3服務(wù)器的地址,端口號(hào),及連接服務(wù)器時(shí)的最大超時(shí)時(shí)間。一般來(lái)說(shuō),只需要給出POP3服務(wù)器的地址就行了。
Function open(){if($this->hostname=='')
{$this->err_str='無(wú)效的主機(jī)名!!';
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服務(wù)器失敗,錯(cuò)誤信息:'.$err_str.'錯(cuò)誤號(hào):'.$err_no;
return false;
} else { $this->getresp();
if($this->debug)
$this->outdebug($this->resp);
if (substr($this->resp,0,3)!='+OK')
{$this->err_str='服務(wù)器返回?zé)o效的信息:'.$this->resp.'請(qǐng)檢查POP服務(wù)器是否正確';
return false; }
$this->state='AUTHORIZATION';
return true;
}
}
該方法不需要任何參數(shù)就可建立與POP3服務(wù)器的sock連接。該方法又用到了另一個(gè)類中的方法$this->getresp();下面是這個(gè)方法的聲明:
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)=='rn')
{
$this->resp=strtok($this->resp,'rn');
return true;
}}}
這個(gè)方法取得服務(wù)器端的返回信息并進(jìn)行簡(jiǎn)單的處理:去掉最后的回車換行符,將返回信息保存在resp這個(gè)內(nèi)部變量中。這個(gè)方法在后面的多個(gè)操作中都將用到。另外,還有個(gè)小方法也在后面的多個(gè)操作中用到:
Function outdebug($message){ echo htmlspecialchars($message).'<br>n';}
它的作用就是把調(diào)試信息$message顯示出來(lái),并把一些特殊字符進(jìn)行轉(zhuǎn)換以及在行尾加上<br>標(biāo)簽,這樣是為了使其輸出的調(diào)試信息便于閱讀和分析。
建立起與服務(wù)器的sock連接之后,就要給服務(wù)器發(fā)送相關(guān)的命令了(請(qǐng)參見上面的與服務(wù)器對(duì)話的過(guò)程)從上面對(duì) POP對(duì)話的分析可以看到,每次都是發(fā)送一條命令,然后服務(wù)器給予一定的回應(yīng),如果命令的執(zhí)行是對(duì)的,回應(yīng)一般是以+OK開頭,后面是一些描述信息,所以,我們可以做一個(gè)通過(guò)發(fā)送命令的方法:
Function command($command,$return_lenth=1,$return_code='+'){ if ($this->connection==0) { $this->err_str='沒有連接到任何服務(wù)器,請(qǐng)檢查網(wǎng)絡(luò)連接';
return false; }
if ($this->debug) $this->outdebug('>>> $command');
if (!fputs($this->connection,'$commandrn'))
{
$this->err_str='無(wú)法發(fā)送命令'.$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.' 命令服務(wù)器返回?zé)o效:'.$this->resp;
return false;
}
else
return true;
}}
這個(gè)方法可以接受三個(gè)參數(shù): $command--> 發(fā)送給服務(wù)器的命令; $return_lenth,$return_code ,指定從服務(wù)器的返回中取多長(zhǎng)的值做為命令返回的標(biāo)識(shí)以及這個(gè)標(biāo)識(shí)的正確值是什么。對(duì)于一般的pop操作來(lái)說(shuō),如果服務(wù)器的返回第一個(gè)字符為'+',則可以認(rèn)為命令是正確執(zhí)行了。也可以用前面提到過(guò)的三個(gè)字符'+OK'做為判斷的標(biāo)識(shí)。
下面介紹的幾個(gè)方法則可以按照前述收取信件的對(duì)話去理解,因?yàn)橛嘘P(guān)的內(nèi)容已經(jīng)在前面做了說(shuō)明,因此下面的方法不做詳細(xì)的說(shuō)明,請(qǐng)參考其中的注釋:
Function Login($user,$password) //發(fā)送用戶名及密碼,登錄到服務(wù)器{
if($this->state!='AUTHORIZATION') {
$this->err_str='還沒有連接到服務(wù)器或狀態(tài)不對(duì)';
return false; }
if (!$this->apop) //服務(wù)器是否采用APOP用戶認(rèn)證 {
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,'rn');
if (!$this->command('APOP $user '.md5($this->greeting.$password),3,'+OK')) return false;
}
$this->state='TRANSACTION'; // 用戶認(rèn)證通過(guò),進(jìn)入傳送模式
return true;}
Function stat() // 對(duì)應(yīng)著stat命令,取得總的郵件數(shù)與總的大小{if($this->state!='TRANSACTION') {
$this->err_str='還沒有連接到服務(wù)器或沒有成功登錄';
return false; }
if (!$this->command('STAT',3,'+OK')) return false;
else
{
$this->resp=strtok($this->resp,' ');
$this->messages=strtok(' '); // 取得郵件總數(shù)
$this->size=strtok(' '); //取得總的字節(jié)大小
return true; }}
Function listmail($mess=null,$uni_id=null) //對(duì)應(yīng)的是LIST命令,取得每個(gè)郵件的大小及序號(hào)。一般來(lái)說(shuō)用到的是List命令,如果指定了$uni_id ,則使用UIDL命令,返回的是每個(gè)郵件的標(biāo)識(shí)符,事實(shí)上,這個(gè)標(biāo)識(shí)符一般是沒有什么用的。取得的各個(gè)郵件的大小返回到類的內(nèi)部變量mail_list這個(gè)二維數(shù)組里。
{if($this->state!='TRANSACTION') {
$this->err_str='還沒有連接到服務(wù)器或沒有成功登錄';
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) // 取得郵件的內(nèi)容,$num是郵件的序號(hào),$line是指定共取得正文的多少行。有些時(shí)候,如郵件比較大而我們只想先查看郵件的主題時(shí)是必須指定行數(shù)的。默認(rèn)值$line=-1,即取回所有的郵件內(nèi)容,取得的內(nèi)容存放到內(nèi)部變量$head,$body兩個(gè)數(shù)組里,數(shù)組里的每一個(gè)元素對(duì)應(yīng)的是郵件源代碼的一行。
{
if($this->state!='TRANSACTION') { $this->err_str='不能收取信件,還沒有連接到服務(wù)器或沒有成功登錄';
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!='.') // . 號(hào)是郵件結(jié)束的標(biāo)識(shí) {
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)=='') // 郵件頭與正文部分的是一個(gè)空行
$is_head=false;
if ($is_head)
$this->head[]=$this->resp;
else
$this->body[]=$this->resp;
$this->getresp();
}
return true; } } // end function
function dele($num) // 刪除指定序號(hào)的郵件,$num 是服務(wù)器上的郵件序號(hào)
{
if($this->state!='TRANSACTION') {
$this->err_str='不能刪除遠(yuǎn)程信件,還沒有連接到服務(wù)器或沒有成功登錄';
return false; }
if (!$num) {
$this->err_str='刪除的參數(shù)不對(duì)';
return false; }
if ($this->command('DELE $num ',3,'+OK')) return true;
else
return false;}
通過(guò)以上幾個(gè)方法,我們已經(jīng)可以實(shí)現(xiàn)郵件的查看、收取、刪除的操作,不過(guò)別忘了最后要退出,并關(guān)閉與服務(wù)器的連接,調(diào)用下面的這個(gè)方法:
Function Close(){
if($this->connection!=0) {
if($this->state=='TRANSACTION')
$this->command('QUIT',3,'+OK');
fclose($this->connection);
$this->connection=0;
$this->state='DISCONNECTED'; }
}
