亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > PHP > 正文

PHP文件上傳源碼分析(RFC1867)

2024-09-04 11:45:02
字體:
來源:轉載
供稿:網友

而基于HTTP的上傳,相對來說易用性和安全性上就比FTP要增強了很多,可以應用的上傳方式有PUT,WEBDAV,和RFC1867三種,本文將分析在PHP中,是如何基于RFC1867實現文件上傳的.

RFC1867:RCF1867是Form-based File Upload in HTML標準協議,RFC1867標準對HTML做出了兩處修改:

1 為input元素的type屬性增加了一個file選項.

2 input標記可以具有accept屬性,該屬性能夠指定可被上傳的文件類型或文件格式列表.

另外,本標準還定義了一種新的mime類型:multipart/form-data,以及當處理一個帶有enctype=”multipart/form-data” 并且/或含有<input type=”file”>的標記的表單時所應該采取的行為.

舉例來說,當HTML想讓用戶能夠上傳一個或更多的文件時,他可以這么寫,代碼如下:

  1. <form enctype="multipart/form-data" action="upload.php" method=post> 
  2. 選擇文件: 
  3. <input name="userfile" type="file"> 
  4. 文件描述: 
  5. <input name="description" type="text"> 
  6. <input type="submit" value="上傳"> 
  7. </form> 

這個表單,大家一定不陌生,而對于PHP來說,它自己另外定義了一個默認表單元素MAX_FILE_SIZE,用戶可以通過這個隱藏的表單元素來建議PHP最多只容許上傳文件的大小,比如對于上面的例子,我們希望用戶上傳的文件不能大于5000(5k)字節,那么可以如下寫:

  1. <form enctype="multipart/form-data" action="upload.php" method=post> 
  2. <input type="hidden" value="5000" name="MAX_FILE_SIZE"> <!--文件大小--> 
  3. 選擇文件: 
  4. <input name="userfile" type="file"> 
  5. 文件描述: 
  6. <input name="description" type="text"> 
  7. <input type="submit" value="上傳"> 
  8. </form> 

姑且不說,這個MAX_FILE_SIZE是多么的不可靠(所以基于瀏覽器的控制,都是不可靠的), 單純從實現來講,我會慢慢介紹這個MAX_FILE_SIZE是如何起作用的.

當用戶選擇了一個文件(laruence.txt),并填寫好文件描述(”laruence的個人介紹”), 點擊上傳后,發生了什么呢?

表單提交:在用戶確定提交以后,瀏覽器會發送如下類似格式的數據包到form中action屬性指定的頁面(在本例中是upload.php),代碼如下:

  1. //請求頭 
  2. POST /upload.php HTTP/1.0rn 
  3. ... 
  4. Host: www.49028c.comrn 
  5. ... 
  6. Content-length: xxxxxrn 
  7. ... 
  8. Content-type: multipart/form-data, boundary=--------------7d51863950254rn 
  9. ...rnrn 
  10. //開始POST數據內容 
  11. ---------------7d51863950254 
  12. content-disposition: form-data; name="description" 
  13. laruence的個人介紹 
  14. ---------------7d51863950254 
  15. content-disposition: form-data; name="userfile"; filename="laruence.txt" 
  16. Content-Type: text/plain 
  17. ... laruence.txt 的內容... 
  18. ---------------7d51863950254 

接下來,就是服務器,是如何處理這些數據了.

接受上傳:當Web服務器,此處假設為Apache(另外假設PHP是以module方式安裝在Apache上的),接受到用戶的數據時, 首先它根據HTTP請求頭,通過確定MIME TYPE為PHP類型, 然后經過一些過程以后(這部分,可以參看我之前的PHP Life Cycle ppt),最終會把控制權交給PHP模塊.

這個時候,PHP會調用sapi_activate來初始化一個請求,在這個過程中,首先判斷請求類型, 此時是POST, 從而去調用sapi_read_post_data,通過Content-type,找到rfc1867的處理函數rfc1867_post_handler,從而調用這個handler,來分析POST來的數據.

關于rfc1867_post_handler這部分的源代碼,可以在mian/rfc1867.c找到,另外也可以參看我之前的深入理解PHP之文件上傳,其中也列出的源代碼.

然后,PHP通過boundary,對于每一個分段,都通過檢查,是否同時定義了:

name和filename屬性(有名文件上傳)

沒有定義name定義了filename(無名上傳)

定義了name沒有定義filename(普通數據),從而進行不同的處理.代碼如下:

  1. if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) { 
  2.  char *pair=NULL; 
  3.  int end=0; 
  4.  
  5.  while (isspace(*cd)) { 
  6.   ++cd; 
  7.  } 
  8.  
  9.  while (*cd && (pair = php_ap_getword(&cd, ';'))) 
  10.  { 
  11.   char *key=NULL, *word = pair; 
  12.  
  13.   while (isspace(*cd)) { 
  14.    ++cd; 
  15.   } 
  16.  
  17.   if (strchr(pair, '=')) { 
  18.    key = php_ap_getword(&pair, '='); 
  19.  
  20.    if (!strcasecmp(key, "name")) { 
  21.     //獲取name字段 
  22.     if (param) { 
  23.      efree(param); 
  24.     } 
  25.     param = php_ap_getword_conf(&pair TSRMLS_CC); 
  26.    } else if (!strcasecmp(key, "filename")) { 
  27.     //獲取filename字段 
  28.     if (filename) { 
  29.      efree(filename); 
  30.     } 
  31.     filename = php_ap_getword_conf(&pair TSRMLS_CC); 
  32.    }//開源代碼Vevb.com 
  33.   } 
  34.   if (key) { 
  35.    efree(key); 
  36.   } 
  37.   efree(word); 
  38.  } 

在這個過程中,PHP會去檢查普通數據中,是否有MAX_FILE_SIZE.代碼如下:

  1.  /* Normal form variable, safe to read all data into memory */ 
  2. if (!filename && param) { 
  3.  unsigned int value_len; 
  4.  char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC); 
  5.  unsigned int new_val_len; /* Dummy variable */ 
  6.  ...... 
  7.  
  8.  if (!strcasecmp(param, "MAX_FILE_SIZE")) { 
  9.                   max_file_size = atol(value); 
  10.     } 
  11.  
  12.  efree(param); 
  13.  efree(value); 
  14.  continue

有的話,就會按照它的值來檢查文件大小是否超出.代碼如下:

  1. if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { 
  2.  cancel_upload = UPLOAD_ERROR_A; 
  3. else if (max_file_size && (total_bytes > max_file_size)) { 
  4. #if DEBUG_FILE_UPLOAD 
  5.  sapi_module.sapi_error(E_NOTICE, 
  6.   "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved"
  7.    max_file_size, param, filename); 
  8. #endif 
  9.  cancel_upload = UPLOAD_ERROR_B; 

通過上面的代碼,我們也可以看到,判斷分為倆部,第一部分是檢查PHP默認的上傳上限. 第二部分才是檢查用戶自定義的MAX_FILE_SIZE,所以表單中定義的MAX_FILE_SIZE并不能超過PHP中設置的最大上傳文件大小.

通過對name和filename的判斷,如果是文件上傳,會根據php的設置,在文件上傳目錄中創建一個隨機名字的臨時文件,代碼如下:

  1. if (!skip_upload) { 
  2.  /* Handle file */ 
  3.  fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), 
  4.     "php", &temp_filename, 1 TSRMLS_CC); 
  5.  if (fd==-1) { 
  6.   sapi_module.sapi_error(E_WARNING, 
  7.     "File upload error - unable to create a temporary file"); 
  8.   cancel_upload = UPLOAD_ERROR_E; 
  9.  } 

返回文件句柄,和臨時隨機文件名,之后,還會有一些驗證,比如文件名合法,name合法等,如果這些驗證都通過,那么就把內容讀入,寫入到這個臨時文件中,代碼如下:

  1. else if (blen > 0) { 
  2.  wlen = write(fd, buff, blen); //寫入臨時文件. 
  3.  if (wlen == -1) { 
  4.  /* write failed */ 
  5. #if DEBUG_FILE_UPLOAD 
  6.  sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno)); 
  7. #endif 
  8.  cancel_upload = UPLOAD_ERROR_F; 
  9.  } 

當循環讀入完成后,關閉臨時文件句柄,記錄臨時變量名,代碼如下:

zend_hash_add(SG(rfc1867_uploaded_files), temp_filename,strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);

并且生成FILE變量,這個時候,如果是有名上傳,那么就會設置,代碼如下:

$_FILES['userfile'] //name="userfile"

如果是無名上傳,則會使用tmp_name來設置,代碼如下:

$_FILES['tmp_name'] //無名上傳

最終交給用戶編寫的upload.php處理,這時在upload.php中,用戶就可以通過move_uploaded_file來操作剛才生成的文件了.

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲一区www| 精品综合久久久久久97| 高清一区二区三区日本久| 欧美视频免费在线观看| 久久电影一区二区| 欧美日韩国产综合视频在线观看中文| 欧美在线一区二区三区四| 亚洲精品乱码久久久久久金桔影视| 92裸体在线视频网站| 97久久精品国产| 国产成人精品在线播放| 国产午夜精品免费一区二区三区| 亚洲精品国产成人| 久久久久这里只有精品| 欧美极品美女视频网站在线观看免费| 日韩激情视频在线| 亚洲精品按摩视频| 久久久久久久影院| 亚洲资源在线看| 国产成人精品久久久| 国产精品爽爽爽爽爽爽在线观看| 啊v视频在线一区二区三区| 精品偷拍各种wc美女嘘嘘| 成人免费观看网址| 久久99国产精品久久久久久久久| 这里只有精品视频在线| 社区色欧美激情 | 91av视频导航| 中文字幕精品久久久久| 国模精品视频一区二区三区| 亚洲成人精品久久| 成人a在线视频| 亚洲二区中文字幕| 成人免费网视频| 国产成人亚洲精品| 亚州精品天堂中文字幕| 国产精品久久99久久| 亚洲激情视频在线| 国语自产精品视频在线看| 亚洲精品中文字幕av| 粗暴蹂躏中文一区二区三区| 亚洲黄色av女优在线观看| 粉嫩老牛aⅴ一区二区三区| 国产精品v片在线观看不卡| 成人www视频在线观看| 黄网站色欧美视频| 亚洲精品免费一区二区三区| 欧美大片欧美激情性色a∨久久| 日韩av在线看| 在线电影欧美日韩一区二区私密| 亚洲缚视频在线观看| 久久精品久久久久久| 欧美日韩中文字幕日韩欧美| 精品久久久久久久久久久久久| 欧美日本精品在线| 茄子视频成人在线| 亚州国产精品久久久| 国产成人一区二区| 久久久久久久网站| 国产丝袜精品第一页| 这里只有精品久久| 成年无码av片在线| 国产不卡av在线| 久久久久久亚洲精品中文字幕| 国产精品丝袜久久久久久高清| 国产v综合ⅴ日韩v欧美大片| 亚洲第一免费播放区| 国产精品免费网站| 日韩精品视频观看| 亚洲跨种族黑人xxx| 欧美色播在线播放| 亚洲精品乱码久久久久久金桔影视| 91极品视频在线| 久热精品在线视频| 亚洲成人av资源网| 久久精品精品电影网| 成人激情免费在线| 久久久久久亚洲精品中文字幕| 欧美性猛交丰臀xxxxx网站| 欧美激情第6页| 高清欧美性猛交xxxx| 欧美成人精品在线| 成人国产精品色哟哟| 亚洲欧洲成视频免费观看| 亚洲一区二区日本| 国语自产精品视频在线看| 久久精品国产69国产精品亚洲| 亚洲第一中文字幕在线观看| 日韩高清电影好看的电视剧电影| 韩日精品中文字幕| 亚洲视频999| 精品国产一区二区三区四区在线观看| 欧美另类在线观看| 国产偷国产偷亚洲清高网站| 亚洲精品色婷婷福利天堂| 亚洲综合精品一区二区| 欧美裸身视频免费观看| 亚洲精品网址在线观看| 一区二区三区视频观看| 亚洲韩国日本中文字幕| 久久99久久亚洲国产| 国产日韩欧美视频在线| 日韩av在线天堂网| 亚洲美女动态图120秒| 81精品国产乱码久久久久久| 久久噜噜噜精品国产亚洲综合| 欧美精品制服第一页| 国产精品一区二区三区久久| 98午夜经典影视| 少妇高潮久久77777| 97久久精品视频| 国内精品久久久久久| 久久色精品视频| 久久久久久欧美| 亚洲一区二区国产| 国产欧美在线观看| 一区二区三区www| 欧美精品久久久久久久| 久久国产精品久久久| 久久视频国产精品免费视频在线| 午夜精品久久久久久久99热浪潮| 欧美黑人一级爽快片淫片高清| 88xx成人精品| 国产精品青草久久久久福利99| 中文字幕亚洲一区在线观看| 日韩国产欧美精品一区二区三区| 久久综合网hezyo| 一区二区三区四区在线观看视频| 91精品国产综合久久男男| 亚洲欧美日韩精品久久奇米色影视| 成人av在线亚洲| 久久久久久久久亚洲| 亚洲自拍偷拍网址| 91av在线精品| 97在线日本国产| 国产精品观看在线亚洲人成网| 亚洲xxx自由成熟| 亚洲第一中文字幕在线观看| 98精品在线视频| 日韩在线视频网站| 久久6精品影院| 亚洲一区亚洲二区亚洲三区| 色婷婷av一区二区三区在线观看| 国产精品欧美一区二区三区奶水| 日韩小视频网址| 日韩电影在线观看免费| 伊人久久大香线蕉av一区二区| 久久精品人人做人人爽| 日韩一级黄色av| 伊人久久男人天堂| 亚洲黄页网在线观看| 亚洲免费电影在线观看| 日韩欧美一区二区三区久久| 精品国内产的精品视频在线观看| 亚洲男人天堂手机在线| 成人福利视频网| 欧美性少妇18aaaa视频| 亚洲天堂久久av| 欧美www在线| 亚洲自拍偷拍第一页| 亚洲精品www久久久| 欧美在线观看网址综合| 国内偷自视频区视频综合| 久久福利网址导航|