參考了一下網上的文章。俗話說,天下文章一大抄,看你會抄不會抄。關鍵是能為我所用,這是最重要的。廢話不多講,let‘s go。
其實發mail很簡單,php有現成的函數,可以參考php 的 manual,特別是第四個例子,講的很詳細。
關鍵是怎麼把上傳附件跟郵件發送結合起來。關於檔案的上傳,可以參考http://blog.csdn.net/slamdunk3/archive/2005/02/23/299025.aspx 這篇文章。
講一下 檔案上傳的方法及其屬性:
我們假設檔案上傳欄位的名稱如上例所示,為 userfile。名稱可隨意命名。
表單裡可以這樣寫:
<input type=file name=userfile>
提交之後,php利用$_FILES 數組 自動擷取相關參數:
$_FILES['userfile']['name']
用戶端機器檔案的原名稱。
$_FILES['userfile']['type']
檔案的 MIME 類型,需要瀏覽器提供該資訊的支援,例如“image/gif”。
$_FILES['userfile']['size']
已上傳檔案的大小,單位為位元組。
$_FILES['userfile']['tmp_name']
檔案被上傳後在服務端儲存的臨時檔案名稱。
$_FILES['userfile']['error']
和該檔案上傳相關的錯誤碼。['error'] 是在 PHP 4.2.0 版本中增加的。
注: 在 PHP 4.1.0 版本以前該數組的名稱為 $HTTP_POST_FILES,它並不像 $_FILES 一樣是自動全域變數。PHP 3 不支援 $HTTP_POST_FILES 數組。
當 php.ini 中的 register_globals 被設定為 on 時,您可以使用更多的變數。例如,$userfile_name 等價於 $_FILES['userfile']['name'],$userfile_type 等價於 $_FILES['userfile']['type'] 等。請記住從 PHP 4.2.0 開始,register_globals 的預設值為 off,因此我們建議您不要依賴於改設定項而使用剛剛提到的那些附加變數。
檔案被上傳後,預設地會被儲存到服務端的預設臨時目錄中,除非您將 php.ini 中的 upload_tmp_dir 設定為了其它的路徑。服務端的預設臨時目錄可以通過更改 PHP 運行環境的環境變數 TMPDIR 來重新設定,但是在 PHP 指令碼內部通過運行 putenv() 函數來設定是不起作用的。該環境變數也可以用來確認其它的操作也是在上傳的檔案上進行的。
有了這些,我們再看與郵件相關的東西。下面是一個帶附件(一個HTML檔案)電子郵件的例子。
Return-Path:
Date: Mon, 22 May 2000 19:17:29 +0000
From: Someone
To: Person
Message-id: <83729KI93LI9214@example.com>
Content-type: multipart/mixed; boundary="396d983d6b89a"
Subject: Here's the subject
--396d983d6b89a
Content-type: text/plain; charset=iso-8859-1
Content-transfer-encoding: 8bit
This is the body of the email.
--396d983d6b89a
Content-type: text/html; name=attachment.html
Content-disposition: inline; filename=attachment.html
Content-transfer-encoding: 8bit
This is the attached HTML file
--396d983d6b89a--
前面的7行是郵件的頭,其中值得注意的是Content-type頭部分。這個頭告訴郵件程式電子郵件是由一個以上的部分組成的。不含附件的郵件只有一個部分:訊息本身。帶附件的電子通常至少由兩部分組成:訊息和附件。這樣,帶兩個附件的郵件由三部分組成:訊息,第一個附件和第二個附件。
帶附件的電子郵件的不同部分之間用分界線來分隔。分界線在Content--type頭中定義。郵件的每個新部分以兩個連字號(--)和分界線開始。
最後一個分界線後也有兩個連字號,表示這個郵件中沒有其它的部分了。
在每個分界線後有一些行,用來告訴郵件程式這個部分的內容的類型。
比如,看看上面例子中第一個分界線後面的兩行--以Content-type: text/plain開頭的行。這些行說明後面的部分是ISO-8859-1字元集的純文字。跟在第二個分界線後的行告訴郵件程式現在的部分是一個HTML檔案,它的名字是"attachment.html"。
Content-disposition這持告訴郵件程式如果可能就以內嵌的方式顯示附件。現在新的郵件程式會在訊息後顯示HTML的內容。如果Content- disposition被設為attachment,那麼郵件程式就不會顯示HTML檔案的內容,而是顯示一個串連到檔案的表徵圖(或其它的類似的東西)。收件者要看附件的內容,必須點擊這個表徵圖。一般情況下,如果附件是一些文本(包含HTML),Content-disposition會被設為inline,這是因為現在大部分郵件程式能夠不藉助其它瀏覽器而直接顯示附件(文本)的內容。如果附件不是文本(比如圖片或其它類似的內容),Content-disposition 就設為attachment。
我們仿照上面的例子,自己寫一個php程式,可以對提交的 收信人,發送人,信件內容,附件進行處理。
首先建立一個靜態頁面,代碼如下:
<html>
<body>
<form method=post name=sndml action=sendmail.php ENCTYPE="multipart/form-data">
<table>
<tr ><td>寄件者:</td>
<td><input type=text name=from ></td>
</tr>
<tr ><td>接受者:</td>
<td><input type=text name=to ></td>
</tr>
<tr ><td>下載提示:</td>
<td><input type=text name=text ></td>
</tr>
<tr ><td>來源資料檔案:</td>
<td><input type=file name=upload_file size=40></td>
</tr>
<tr><td> </td>
<td><input type="submit" value="確定">
</td>
</tr>
</table>
</form>
</body>
</html>
要注意的是 : 表單裡 ENCTYPE="multipart/form-data" 一定要有。
再來看一下 發送郵件的php程式:
<?php
//常值內容
$text = $_POST['text'];
//標題
$subject = $_POST['subject'];
//寄件者
$from = $_POST['from'];
//接受者
$to = $_POST['to'];
//附件
$file = $_FILES['upload_file']['tmp_name'];
// 定義分界線
$boundary = uniqid( "");
$headers = "Content-type: multipart/mixed; boundary= $boundary\r\n";
$headers .= "From:$from\r\n";
//確定上傳檔案的MIME類型
if($_FILES['upload_file']['type'])
$mimeType = $_FILES['upload_file']['type'];
else
$mimeType ="application/unknown";
//檔案名稱
$fileName = $_FILES['upload_file']['name'];
// 開啟檔案
$fp = fopen($file, "r");
// 把整個檔案讀入一個變數
$read = fread($fp, filesize($file));
//我們用base64方法把它編碼
$read = base64_encode($read);
//把這個長字串切成由每行76個字元組成的小塊
$read = chunk_split($read);
//現在我們可以建立郵件的主體
$body = "--$boundary
Content-type: text/plain; charset=iso-8859-1
Content-transfer-encoding: 8bit
$text
--$boundary
Content-type: $mimeType; name=$fileName
Content-disposition: attachment; filename=$fileName
Content-transfer-encoding: base64
$read
--$boundary--";
//發送郵件
if(mail($to, $subject,$body,$headers))
print "OK! the mail $from --- $to has been send<br>";
else
print "fail to send mail <br>";
?>
看不明白沒關係,我來說明一下:
1,郵件標頭的構造 :一般包括
內容類型(Content-type)要發送附件,設定為 multipart/mixed 意思是多個部分 (郵件本身+附件)。
boundary ,就是上面提到的分界線,他的值用php內建的 uniqid();函數取得
接受方,抄送等,在後面加上 From: Cc:。與上面的 Content-type boundary 之間用 \r\n 分割 。
2 郵件體
如果是純文字的郵件內容 它的格式如下:
Content-type: text/plain; charset=iso-8859-1
Content-transfer-encoding: 8bit
後面再緊接著加上 郵件的常值內容。
如果是附件:
Content-type: $mimeType; name=$fileName
Content-disposition: attachment; filename=$fileName
Content-transfer-encoding: base64
後面再緊接著加上 附件內容。
$mimeType 是附件的 MIME類型。 可以用 $_FILES['upload_file']['type'] 得到。
$fileName 就是附件的名字了
郵件常值內容和附件之間用 boundary 分割。
有人會問,附件內容是什嗎?附件內容就是用read函數讀入所上傳的附件,然後再把它經過base64編碼之後再用chunk_split 大卸N塊,每塊大小是預設的76字元。
好了,現在再去看那段程式,應該沒什麼問題了吧?把相應的變數帶入mail函數裡面就ok了。
以上程式在 PHP Version 4.3.8 freeBSD 下測試通過。
參考文章:《php 發送帶附件的郵件 作者: cn-linux》