| 為大家深入介紹php檔案上傳的相關原理,有需要的朋友,可以參考下。 很多的php 教程中,都會介紹檔案上傳,眾所周知,php檔案上傳是簡單而高效的,今天為大家分析下其原理。 //使用multipart/form-data編碼格式$_FILES系統函數;$_FILES['myFile']['name']檔案名稱$_FILES['myFile']['type']檔案的類型,服務端進行限制image/**image/x-pngapplication/x-zip-compressed$_FILES['myFile']['size']上傳檔案大小$_FILES['myFile']['tmp_name']上傳服務後儲存臨時檔案名稱$_FILES['myFile']['error']錯誤碼;0成功1超過php.ini大小2超過MAX_FILE_SIZE選項指定的值3隻有部分上傳 5上傳檔案大小為0 move_uploaded_file(臨時檔案,目標位置和檔案名稱);上傳後移動檔案到目標位置的函數is_uploaded_file(MIME); 判斷上傳MIME類型的例子:1、html部分 2、檔案上傳代碼 -------------------------------------------PHP檔案上傳的原理及實現 一,表單 1,上傳檔案的表單使用post方式(和get的區別不用說了);還要加上enctype='multipart/form-data'。 2,一般要加上隱藏欄位:,位置在file域前面。value的值是上傳檔案的用戶端位元組限制。據說可以減少檔案超標時用戶端的等待時間,不過我沒覺得有什麼區別。 3,出於安全考慮,file域是不許賦值的。隨便在file域輸入字串,然後按submit也不會有反應。必須是第二個字元是冒號的時候(比如空格跟隨冒號可以上傳一個長度為0位元組的“檔案”),submit才同意“服務”——不過這個是用戶端的措施,跟MAX_FILE_SIZE一樣很容易繞過去。 二,檔案上傳錯誤碼 先抄一段:預定義變數$_FILES數組有5個內容: $_FILES['userfile']['name']——用戶端機器檔案的原名稱 $_FILES['userfile']['type']——檔案的 MIME 類型 $_FILES['userfile']['size']——已上傳檔案的大小,單位為位元組 $_FILES['userfile']['tmp_name']——檔案被上傳後在服務端儲存的臨時檔案名稱 $_FILES['userfile']['error']——和該檔案上傳相關的錯誤碼 其中$_FILES['userfile']['error']的可以有下列取值和意義: 0——沒有錯誤發生,檔案上傳成功。 1——上傳的檔案超過了 php.ini 中 upload_max_filesize 選項限制的值。 2——上傳檔案的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項指定的值。 3——檔案只有部分被上傳。 4——沒有檔案被上傳。 1~3不用說了。 “沒有檔案被上傳”(4)是指表單的file域沒有內容,是Null 字元串。 “檔案上傳成功”(0)不一定真的有檔案上傳了。比如你打了個“c:”給file域,就可以“上傳成功”——錯誤碼是0,['name']是“c:”,['type']是“application/octet-stream”,['size']是0,['tmp_name']是“xxx.tmp”(xxx是伺服器起的名字) 三,檔案大小限制和檢驗 限制上傳檔案大小的因素有 1,用戶端的隱藏欄位MAX_FILE_SIZE的數值(可以被繞開)。 2,伺服器端的upload_max_filesize,post_max_size和memory_limit。這幾項不能夠用指令碼來設定。 3,自訂檔案大小限制邏輯。即使伺服器的限制是能自己決定,也會有需要個別考慮的情況。所以這個限制方式經常是必要的。 我碰見的一種情況可能不是普遍性的,說明一下。如果檔案比伺服器端限制(upload_max_filesize)大很多,但也還沒達到或接近post_max_size或者memory_limit,$_FILES就會“崩潰”——結果是$_FILES['userfile']變成了“Undefined index”,當然是什麼檢驗也做不到了。 伺服器端限制的檢驗優先於用戶端限制的檢驗。就是說,如果兩個限制是一樣的,而檔案過大了,$_FILES['userfile']['error']會出錯誤碼1。只有用戶端限制比伺服器端限制小到一定“程度”,而且檔案大小超過兩者的時候,才會出現錯誤碼2(難道這跟我感覺MAX_FILE_SIZE沒起到預想的作用是一個原因?)。上述的“程度”,在我的機器上實驗在3~4K之間——我的機器設定的伺服器端限制為2M……因為沒什麼意味,就沒有追求精確的規律。 出現錯誤碼1或2的時候: $_FILES['userfile']['name']為用戶端機器檔案的原名稱 $_FILES['userfile']['type']為空白字串 $_FILES['userfile']['size']為0 $_FILES['userfile']['tmp_name']為空白字串 四,檔案路徑檢驗 file域無輸入,錯誤碼為4(無檔案上傳) $_FILES['userfile']['name']為空白字串 $_FILES['userfile']['type']為空白字串 $_FILES['userfile']['size']為0 $_FILES['userfile']['tmp_name']為空白字串 file域是非檔案路徑的字串(不考慮用戶端的假“限制”了),錯誤碼是0(“上傳成功”) $_FILES['userfile']['name']為原字串 $_FILES['userfile']['type']為application/octet-stream $_FILES['userfile']['size']為0 $_FILES['userfile']['tmp_name']為一個暫時檔案名稱 五,is_uploaded_file()的傳回值 手冊上面不很詳細地說,用法是: bool is_uploaded_file( string filename) 實際上 is_uploaded_file($_FILES['userfile']['name']); 總是返回FALSE。後來看見別人是用: is_uploaded_file($_FILES['userfile']['tmp_name']); 比較一下: file域無輸入——————返回FALSE——error=>4,name=>'', tmp_name=>'', type=>'', size=>0 file域為非路徑字串——返回 TRUE——error=>0,name=>'xxx',tmp_name=>'yyy',type=>'zzz',size=>0 檔案上傳成功——————返回 TRUE——error=>0,name=>'xxx',tmp_name=>'yyy',type=>'zzz',size=>sss 檔案太大————————返回FALSE——error=>1,name=>'xxx',tmp_name=>'', type=>'', size=>0 檔案太大————————返回FALSE——error=>2,name=>'xxx',tmp_name=>'', type=>'', size=>0 檔案部分上傳——————沒機會實驗 —error=>3 有點懷疑這個函數是怎麼工作的,還是覺得用$_FILES['userfile']['size']檢驗好些。 六,檢驗順序 if($_FILES['userfile']['error']!=4){//有檔案上傳 if($_FILES['userfile']['error']!=3){//全部上傳了 if($_FILES['userfile']['error']!=1){//不超過伺服器端檔案大小限制 if($_FILES['userfile']['error']!=2){//不超過用戶端檔案大小限制 if($_FILES['userfile']['size']>0){//確實是檔案 if(......){//自訂檔案大小檢驗邏輯 if(......){//自訂檔案類型檢驗邏輯 if(move_uploaded_file($_FILES['userfile']['tmp_name'],...))//移動檔案 //.......... } else give_a_message(...); } else give_a_message(...); } else give_a_message(...); } else give_a_message(...); } else give_a_message(...); } else give_a_message(...); } else give_a_message(...); }附代碼:------------------------------1)、test.php: 2)、upload.php "; if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { print "File is valid, and was successfully uploaded. Here's some more debugging info:\n"; print_r($_FILES); } else { print "Possible file upload attack! Here's some debugging info:\n"; print_r($_FILES); } print ""; ?> |