<form action="getfile.php" method="post" enctype="multipart/form-data">
上傳檔案: <input type="file" name="felixfile" size=16>
<input type="submit" value="上傳">
<input type="hidden" name="MAX_FILE_SIZE" value="40960">
</form>

<?
echo  $_FILES['felixfile']['tmp_name'];
echo  $_FILES['felixfile']['name'];
copy($_FILES['felixfile']['tmp_name'],"./upload/".$_FILES['felixfile']['name']);
?>

 

在檔案上傳這個章節中,顧名思義就是介紹如何利用瀏覽器的介面搭配PHP函示上傳檔案,在這之前於php.ini中有幾點必須注意到的是:

  1. file_uploads 項目是否設定為On(預設)。
  2. upload_max_filesize 為上傳檔案的最大限制,預設為2MB(2M)。

  如果想要使上傳的檔案大小上限增加時,除了將上述的upload_max_filesize加大以外,另外還需要考慮到:

  1. max_execution_time 最大執行時間,預設為30秒。
  2. memory_limit 記憶體限制,預設為8M。
  3. post_max_size POST的資料量限制,預設為8M。

13-1 準備工作
13-2 檔案上傳
 [13-2-1 錯誤判斷]
 [13-2-2 複製檔案]

13-3 寫入記錄
13-4 檢視頁面
13-5 刪除檔案與記錄
13-6 下載檔案
13-7 專題延伸

13-2 檔案上傳

  首先我們便來看看檔案上傳,PHP中一個典型的檔案上傳流程是:

  1. 提供上傳檔案
  2. 判斷錯誤
  3. 複製暫存檔案至指定目錄下(copy()函示)。

【範例檔案】 -- 開啟範例檔案upload.php


 Step1. 開啟頁面後,請在表格中加上一個隱藏欄位、一個檔案欄位、一個按鈕,必須注意的是隱藏欄位必須是表單中的第一個元件。


圖13-2-01

 Step2. 接著將隱藏欄位命名為MAX_FILE_SIZE、值為1000000,這是預設用來限制上傳檔案大小的欄位,它應該被放在表單中所有元件中的第一個位置,限制的上傳值即為該欄位值,單位為Byte。

  檔案欄位命名為myfile,最後表單的『動作』目標設至add.php,編碼則是multipart/form-data。


圖13-2-02

圖13-2-03

圖13-2-04

  接著看到的是index.php表單中動作目標的add.php,我們先來瞭解該如何取得上傳檔案的資訊。

【範例檔案】 -- 開啟範例檔案add.php

  開啟檔案後我們在頁面上方加上如下程式碼。

圖13-2-05

  在這裡我們可以看到有五個資訊輸出,包括了檔案名稱、大小、格式、暫存名稱、錯誤代碼,這些都是預設就可以使用的變數與資訊,其中的 myfile 即為index.php中的檔案欄位名稱,也就是說若你將檔案欄位名稱命名為ourfile,這裡的各個資訊便需使用$_FILES['ourfile']['xxx']。

其中的:

  • $_FILES['myfile']['name'] 這是使用者上傳的原始檔案名稱。
  • $_FILES['myfile']['size'] 為檔案大小,單位為Byte。
  • $_FILES['myfile']['tmp_name'] 為檔案上傳完畢後於伺服器中暫存的位置。
  • $_FILES['myfile']['type'] 為檔案的MIME格式。
  • $_FILES['myfile']['error'] 檔案上傳的錯誤代碼,在後面我們會針對這個變數的值做處理(PHP 4.2.0以上版本才支援)。

  其實我們在index.php所做的幾個簡單步驟便已經做到將檔案上傳的功能,只不過這時候檔案會是位於$_FILES['myfile']['tmp_name']的位置(伺服器中的暫存位置),其中的MAX_FILE_SIZE隱藏欄位若沒有加上這個欄位也沒有關係,自然有upload_max_filesize等項目來限制上傳的大小,這時候先來試試前面所做的是否都能運作。


圖13-2-06 選擇一個小於1MB的檔案上傳


圖13-2-07 顯示該上傳檔案的相關資訊


[錯誤判斷]


  如果我們在add.php中可以看到相關的資訊,那麼代表前面的步驟沒有問題,接著下來便針對上傳的錯誤做相關的提示訊息,錯誤訊息前面提過會記錄在$_FILES['myfile']['error']。


 Step1. 同樣是在add.php中,我們在剛剛的程式碼下加上下列程式。

圖13-2-08

08  if($_FILES['myfile']['error'] > 0){
09   switch($_FILES['myfile']['error']){
10    case 1 : die("檔案大小超出 php.ini:upload_max_filesize 限制");
11    case 2 : die("檔案大小超出 MAX_FILE_SIZE 限制");
12    case 3 : die("檔案僅被部分上傳");
13    case 4 : die("檔案未被上傳");
14   }
15  }


  其中$_FILES['myfile']['error']若等於0則代表上傳的過程中沒有錯誤,當$_FILES['myfile']['error']大於0時,程式會依據$_FILES['myfile']['error']的值輸出相關的提示訊息並終止程式的執行。

  這時候我們可以找一個大於1MB的檔案上傳,可以看到的是只有檔案名稱是正常顯示的,錯誤代碼為2因為上傳的檔案大小超過index.php中MAX_FILE_SIZE隱藏欄位的值。

圖13-2-09

[複製檔案]

  在瞭解MAX_FILE_SIZE隱藏欄位與如何利用$_FILES['myfile']['error']所提供的資訊來除錯後,接著要做的便是將檔案由伺服器的暫存位置複製至我們所需要的位置,在前面的程式碼下方輸入下列程式。


圖13-2-10

17  if(is_uploaded_file($_FILES['myfile']['tmp_name'])){
18   $DestDIR = "files";
19   if(!is_dir($DestDIR) || !is_writeable($DestDIR))
20    die("目錄不存在或無法寫入");
21
22   $File_Extension = explode(".", $_FILES['myfile']['name']);
23   $File_Extension = $File_Extension[count($File_Extension)-1];
24   $ServerFilename =date("YmdHis") . "." . $File_Extension;
25   copy($_FILES['myfile']['tmp_name'] , $DestDIR . "/" . $ServerFilename );
26  }


  一般我們先會用is_uploaded_files()來確認檔案是否是真正被上傳與存在於伺服器上(也是為了安全性),因為表單送出之後檔案的位置與名稱會在伺服器的暫存目錄中,因此用is_uploaded_file($_FILES['myfile']['tmp_name'])來判斷,若是才執行下面的動作,接著的程式主要是定義檔名、判斷目錄、複製檔案三個步驟。

  18列中我們定義了目的的資料夾files,我們可以用is_dir與is_writeable來判斷目錄是否存在與目錄是否可以寫入,19列中兩個函示前面都被加了驚嘆號(!),這會將回傳的TRUE、FALSE給反相,也就是TRUE變為FALSE、FALSE變為TRUE,因此19、20列我們可以看做是『若目錄不存在 或(||) 目錄無法寫入,則輸出目錄不存在或無法寫入,然後終止程式執行』。

22  $File_Extension = explode(".", $_FILES['myfile']['name']);


  22與23列都在處理取得檔案副檔名,22列中的explode(".", $_FILES['myfile']['name'])可以看成,將$_FILES['myfile']['name']的值,以逗點(.)作為分隔,傳回陣列的形式,假設$_FILES['myfile']['name']等於DSC012345.JPG,那麼以逗號分隔後即為DSC012345與JPG,而這兩個值會被丟到左邊的$File_Extension變數,結果即為$File_Extension[0]=DSC012345、$File_Extension[1]=JPG。

  在22列執行的結果我們可以看到$File_Extension[1]的值為副檔名,但是有的檔案可能會有好幾個逗點例如DSC.012345.JPG,那麼這個時候副檔名的位置應該就是$File_Extension[2],23列的程式主要在處理這個狀況。

23  $File_Extension = $File_Extension[count($File_Extension)-1];


  我們可以注意到副檔名一定會是在最後的位置,這時候可以利用count()來統計陣列的元素個數,這個值會與副檔名的陣列索引值差1,因此$File_Extension[count($File_Extension)-1]可以用來確保索引(把整個粗體部分看成1個索引)一定在副檔名的位置,最後我們將這個值重新丟回$File_Extension,這時候$File_Extension便不再是陣列而是儲存副檔名了。

24  $ServerFilename =date("YmdHis") . "." . $File_Extension;


  為了避免檔案名稱重複而使伺服器上的檔案被覆蓋,因此這個檔案上傳系統的規劃是,伺服器上的檔名是使用上傳的 年月日時分秒.副檔名 作為檔名,我們在24列定義這個變數叫做$ServerFilename,主檔名的部分使用date()函示產生年月日時分秒,接著連接一個逗點與副檔名變數$File_Extension,在使用者下載檔案的時候我們會用一點技巧使其能夠直接儲存為原始檔名。。

25   copy($_FILES['myfile']['tmp_name'] , $DestDIR . "/" . $ServerFilename );


  前面我們僅是將檔案上傳至伺服器的暫存目錄中,這時候必須使用copy()函示來將檔案複製到我們所要的目錄中,copy()函示的語法為 copy( 來源路徑檔名 , 目的路徑檔名 ) ,來源的路徑檔名已經在$_FILES['myfile']['tmp_name']中了,而目的位置則是用 $DestDIR . "/" . $ServerFilename 連接成一個相對路徑。

  講了這麼多後直接使用瀏覽器開啟網頁來真正上傳一次檔案吧,上傳完畢後這次就可以在files目錄下真正看到所上傳的檔案,檔名便為上傳的時間。

圖13-2-11

Tips

files目錄於Windows系統中必須【沒有】唯讀屬性,若於Unix-Like系統中則必須有寫入權限,一般會設為667。

arrow
arrow
    全站熱搜

    Felix 發表在 痞客邦 留言(0) 人氣()