php的文件上傳入門教程(實(shí)例講解)
一、文件上傳
為了讓客戶端的用戶能夠上傳文件,我們必須在用戶界面中提供一個(gè)表單用于提交上傳文件的請(qǐng)求。由于上傳的文件是一種特殊數(shù)據(jù),不同于其它的post數(shù)據(jù),所以我們必須給表單設(shè)置一個(gè)特殊的編碼:
以上的enctype屬性,你可能不太熟悉,因?yàn)檫@常常會(huì)被忽略掉。但是,如果http post請(qǐng)求中既有常規(guī)數(shù)據(jù),又包含文件類數(shù)據(jù)的話,這個(gè)屬性就應(yīng)該顯示加上,這樣可以提高針對(duì)各種瀏覽器的兼容性。
接下來(lái),我們得向表單中添加一個(gè)用于上傳文件的字段:
上述文件字段在各種瀏覽器中可能表現(xiàn)會(huì)有所不同。對(duì)于大多數(shù)的瀏覽器,上述字段都會(huì)被渲染成一個(gè)文本框加上一個(gè)瀏覽按鈕。這樣,用戶既可以自行輸入文件的路徑到文本框中,也可以通過(guò)瀏覽按鈕從本地硬盤上選擇所要上傳的文件。但是,在蘋果的Safari中,貌似只能使用瀏覽這種方式。當(dāng)然,你也可以自定義這個(gè)上傳框的樣式,使它看起來(lái)比默認(rèn)的樣式優(yōu)雅些。
下面,為了更好的闡述怎么樣處理文件上傳,舉一個(gè)完整的例子。比如,以下一個(gè)表單允許用戶向我的本地服務(wù)器上上傳附件:
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="attachment">
<input type="submit" value="上傳附件">
</form>
提示:可以通過(guò)php.ini中的upload_max_filesize來(lái)設(shè)置允許上傳文件的最大值。另外,還有一個(gè)post_max_size也可以用來(lái)設(shè)置允許上傳的最大表單數(shù)據(jù),具體意思就是表單中各種數(shù)據(jù)之和,所以你也可以通過(guò)設(shè)置這個(gè)字段來(lái)控制上傳文件的最大值。但是,注意后者的值必須大于前者,因?yàn)榍罢邔儆诤笳叩囊徊糠直韱螖?shù)據(jù)。
![]() |
圖1. 顯示在在firefox中的上傳表單
當(dāng)這個(gè)表單提交的時(shí)候,http請(qǐng)求會(huì)被發(fā)送到upload.php。為了顯示具體哪些信息可以在upload.php中使用,我在upload.php將其打印出來(lái):
header('Content-Type: text/plain');
print_r($_FILES);
下面來(lái)做個(gè)試驗(yàn),假如我通過(guò)以上表單上傳一個(gè)本博客的logo到我的本地服務(wù)器www.360weboy.me/upload.php,看看在upload.php中會(huì)輸出什么信息:
(
[attachment] => Array
(
[name] => boy.jpg
[type] => image/jpeg
[tmp_name] => D:\xampp\tmp\php1168.tmp
[error] => 0
[size] => 11490
)
)
以上就是文件上傳后,在全局?jǐn)?shù)組中的關(guān)于當(dāng)前上傳文件的所有信息。但是,我們是否能夠保證這些信息是安全的,假如name或者其它信息被篡改過(guò)了呢?我們時(shí)刻需要對(duì)來(lái)自客戶端的信息保持警惕!
具體的http請(qǐng)求的各個(gè)部分
為了更好的理解文件上傳,我們必須核對(duì)下客戶端發(fā)送的http請(qǐng)求中到底包含了那些具體的信息。先前我上傳的附件是本博客的logo,因?yàn)槭菆D片,不太適合我們做以上實(shí)驗(yàn)。所以,我重新上傳一個(gè)test.text文本文件,其中具體包含了以下內(nèi)容:
360w
360days
Life Of A Web Boy
Okay。現(xiàn)在我上傳這個(gè)文本文件,在upload.php中會(huì)輸出:
Array
(
[attachment] => Array
(
[name] => test.txt
[type] => text/plain
[tmp_name] => D:\xampp\tmp\php51C0.tmp
[error] => 0
[size] => 40
)
)
我們?cè)賮?lái)看下相關(guān)的瀏覽器發(fā)送的http post請(qǐng)求(一些可選的頭部我省略了):
POST /upload.php HTTP/1.1
Host: www.360weboy.me
Referer: http://www.360weboy.me/
multipart/form-data; boundary=---------------------------24464570528145
Content-Length: 234
-----------------------------24464570528145
Content-Disposition: form-data; name="attachment"; filename="test.txt"
Content-Type: text/plain
360weboy
360days
Life Of A Web Boy
-----------------------------24464570528145--
從上面的請(qǐng)求格式中有幾個(gè)字段我們要關(guān)注下的,分別是name, filename以及Content-Type.它們分別表示上傳文件框在form表單中的字段名-attachment,用戶從本地硬盤中上傳的文件名 – test.txt,以及上傳的文件格式 – text/plain(代表文本文件)。然后,我們看到一行空行下面的,就是這個(gè)上傳文件中的具體內(nèi)容。
二、安全性的加強(qiáng)
為了加強(qiáng)文件上傳中的安全性,我們需要檢查下$_FILES全局?jǐn)?shù)組中的tmp_name和size。為了確保tmp_name指向的文件確實(shí)是剛剛用戶在客戶端上傳的文件,而不是指向的類似/etc/passwd,可以使用php中的函數(shù)is_uploaded_file()來(lái)進(jìn)行下判斷:
$filename = $_FILES['attachment']['tmp_name'];
if (is_uploaded_file($filename)) {
/* 是一個(gè)上傳的文件. */
}
某些情況下,用戶上傳文件后,可能會(huì)將上傳成功的文件的內(nèi)容顯示給用戶看下,那么上述代碼的檢查尤其重要。
另外一個(gè)需要檢查的就是上傳文件的mime-type, 也就是上述upload.php中輸出數(shù)組的type字段。 我在第一個(gè)例子中上傳的是一個(gè)圖片,所以$_FILES['attachment']['type']的值為'image/jpeg'。 如果打算在服務(wù)器端只接受image/png, image/jpeg, image/gif, image/x-png 以及 image/p-jpeg這些mime-type的圖片,可以用類似下面的代碼了進(jìn)行檢查(只是舉個(gè)例子,具體代碼,比如報(bào)錯(cuò)等,應(yīng)該遵循你的系統(tǒng)中的機(jī)制):
$allow_mimes = array(
'image/png',
'image/x-png',
'image/gif',
'image/jpeg',
'image/pjpeg'
);
$image = $_FILES['attachment'];
if(!in_array($image['type'], $allow_mimes)) {
die('對(duì)不起, 你上傳的文件格式不準(zhǔn)確;我們只接受圖片文件.');
}
// 繼續(xù)處理上傳的圖片文件
正如你看到的,我們已經(jīng)保準(zhǔn)了文件的mime-type是符合服務(wù)器端的要求的。但是,這樣是不是就可以防止惡意用戶上傳其它有害文件,還是不夠的,因?yàn)檫@個(gè)mime-type惡意用戶是可以偽裝的。 比如用戶做了一張jpg圖片,在圖片的元數(shù)據(jù)中寫入了一些惡意的php代碼,然后保存為后綴名為php的文件。當(dāng)這個(gè)惡意文件上傳的時(shí)候,將順利通過(guò)服務(wù)器端對(duì)于mime-type的檢查,被認(rèn)為是一張圖片,里面的危險(xiǎn)的php代碼將會(huì)被執(zhí)行。具體的圖片的元數(shù)據(jù)類似如下:
File name : image.jpg
File size : 182007 bytes
File date : 2012:11:27 7:45:10
Resolution : 1197 x 478
Comment : passthru($_POST['cmd']); __halt_compiler();
我們可以看到,在圖片元數(shù)據(jù)的Comment字段中加入了php代碼。所以,很顯然,為了防止類似危險(xiǎn)情況發(fā)生,還必須對(duì)上傳文件的擴(kuò)展名進(jìn)行一次必要的檢查。下面的代碼對(duì)前面的檢查Mime-type的代碼進(jìn)行了加強(qiáng):
$allow_mimes = array(
'image/png' => '.png',
'image/x-png' => '.png',
'image/gif' => '.gif',
'image/jpeg' => '.jpg',
'image/pjpeg' => '.jpg'
);
$image = $_FILES['attachment'];
if(!array_key_exists($image['type'], $allow_mimes )) {
die('對(duì)不起, 你上傳的文件格式不準(zhǔn)確;我們只接受圖片文件.');
}
// 獲取略去后綴名的文件名:
$filename = substr($image['name'], 0, strrpos($image['name'], '.'));
// 添加后綴名
$filename .= $allow_mimes[$image['type']];
// 繼續(xù)處理上傳的文件
通過(guò)上述的代碼,我們確保即使上傳的圖片的元文件中包含了php代碼的話,圖片文件會(huì)被重名為后綴名為圖片格式的文件,所以其中的php代碼也不會(huì)被執(zhí)行了。上述代碼對(duì)正常的上傳的圖片也不會(huì)有任何負(fù)面影響。
進(jìn)行了上述的幾步提高安全性的檢查步驟后,如果你只是要把上傳的文件保存到一個(gè)指定的目錄中,那么就可以使用php的默認(rèn)函數(shù)move_uploaded_file來(lái)實(shí)現(xiàn)了:
$tmp_filename = $_FILES['attachment']['tmp_name'];
$filename = '/path/to/attachment.txt';
if (move_uploaded_file(tmp_filename, $filename)) {
/* $temp_filename 保存在臨時(shí)目錄中的上傳文件, 然后成功將其保存到對(duì)應(yīng)目錄下的attachment.txt文件中. */
}
你也許還要對(duì)上傳文件的大小進(jìn)行限制,那么你可以通過(guò)filesize函數(shù)來(lái)獲取上傳文件的大小,進(jìn)行判斷后做進(jìn)一步處理,這具體就不在這將了,自己去折騰吧。
好了,關(guān)于文件上傳暫時(shí)就寫到這里吧。希望這篇入門篇文章對(duì)你有所幫助。
- PHP設(shè)置圖片文件上傳大小的具體實(shí)現(xiàn)方法
- php文件上傳的簡(jiǎn)單實(shí)例
- 簡(jiǎn)單的php文件上傳(實(shí)例)
- php jquery 多文件上傳簡(jiǎn)單實(shí)例
- php多文件上傳下載示例分享
- php設(shè)置允許大文件上傳示例代碼
- PHP實(shí)現(xiàn)視頻文件上傳完整實(shí)例
- PHP+iFrame實(shí)現(xiàn)頁(yè)面無(wú)需刷新的異步文件上傳
- PHP多個(gè)文件上傳到服務(wù)器實(shí)例
- Thinkphp多文件上傳實(shí)現(xiàn)方法
- PHP文件上傳判斷file是否己選擇上傳文件的方法
- 一個(gè)經(jīng)典的PHP文件上傳類分享
- 配置php.ini實(shí)現(xiàn)PHP文件上傳功能
- php可生成縮略圖的文件上傳類實(shí)例
- php判斷文件上傳類型及過(guò)濾不安全數(shù)據(jù)的方法
- php+jQuery.uploadify實(shí)現(xiàn)文件上傳教程
- php文件上傳你必須知道的幾點(diǎn)
相關(guān)文章
javascript中call apply 與 bind方法詳解
網(wǎng)上文章雖多,大多復(fù)制粘貼,且晦澀難懂,我希望能夠通過(guò)這篇文章,能夠清晰的提升對(duì)apply、call、bind的認(rèn)識(shí),并通過(guò)一些具體的示例給大家展示下這3個(gè)方法的用法,希望大家能夠喜歡。2016-03-03總結(jié)JavaScript在IE9之前版本中內(nèi)存泄露問題
本篇文章給大家總結(jié)了JavaScript在IE9之前版本中內(nèi)存泄露問題,對(duì)此有興趣的朋友可以學(xué)習(xí)下。2018-04-04表單元素的submit()方法和onsubmit事件應(yīng)用概述
表單元素?fù)碛衧ubmit方法,同時(shí)也具有onsubmit事件句柄,用于監(jiān)聽表單提交??梢允褂胑lemForm.submit();方法觸發(fā)表單提交,感興趣的朋友可以了解下,或許對(duì)你有所幫助2013-02-02JavaScript瀏覽器對(duì)象之一Window對(duì)象詳解
下面小編就為大家?guī)?lái)一篇JavaScript瀏覽器對(duì)象之一Window對(duì)象詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06Javascript 按位與運(yùn)算符 (&)使用介紹
Javascript 按位與運(yùn)算符 (&),用于對(duì)兩個(gè) 32 位表達(dá)式執(zhí)行按位“與”運(yùn)算,而一般表達(dá)式里面都是十進(jìn)制整數(shù),此時(shí)需要先轉(zhuǎn)換成對(duì)應(yīng)的二進(jìn)制,然后向前加0,補(bǔ)足32位2014-02-02Javascript中的轉(zhuǎn)義用法實(shí)例代碼
Javascript 中的轉(zhuǎn)義用法一例,需要的朋友可以參考下。2010-11-11