為大家深入介紹php檔案上傳的相關原理,有需要的朋友,可以參考下。
在許多的php 教學中,都會介紹檔案上傳,眾所周知,php檔案上傳是簡單而有效率的,今天為大家分析下其原理。 //使用multipart/form-data編碼格式 $_FILES系統函數; $_FILES['myFile']['name']檔案名稱 $_FILES['myFile']['type']檔案的類型,服務端進行限制 image/** image/x-png application/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部分 <form enctyoe="multipart/form-data" method="post" name="upload"> <input name="upfile" name="name"> </form> 登入後複製 2、檔案上傳程式碼 <?php if(is_uploaded_file($_FILES['myFile']['tmp_name'])){ $upfile = $_FILES['upload']; $name = $upfile['name']; $type = $upfile['type']; $size = $upfile['size']; $tmp_name = $upfile['tmp_name']; $error = $upfile['error']; switch($type){ case 'image/pjpeg' : $ok=1; break } if($ok){ move_uploaded_file($tmp_name,'up/'.$name); }else{ echo "不允许的文件类型"; } } ?> 登入後複製 ------------------------------------------- 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域沒有內容,是空字串。 「檔案上傳成功」(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: <html> <body> <form enctype="multipart/form-data" action="upload.php" method="POST"> <input type="hidden" name="MAX_FILE_SIZE" value="30000" /> Send this file: <input name="userfile" type="file" accept="image/x-png,image/gif,image/jpeg"/> <input type="submit" value="Send File" /> </form> </body> </html> 登入後複製 2)、upload.php <html> <body> <?php $uploaddir = 'images/'; $uploadfile = $uploaddir. $_FILES['userfile']['name']; print "<pre class="brush:php;toolbar:false">"; 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 " 登入後複製 |