請參閱 https://php.dev.org.tw/manual/en/features.file-upload.post-method.php,以取得 $_FILES 陣列的相關文件,這正是我最初來到此頁面的原因。
(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)
$_FILES — HTTP 檔案上傳變數
注意:
這是一個「超全域」或自動全域變數。這僅表示它在腳本中的所有範圍內都可用。不需要使用 global $variable; 在函式或方法中存取它。
請參閱 https://php.dev.org.tw/manual/en/features.file-upload.post-method.php,以取得 $_FILES 陣列的相關文件,這正是我最初來到此頁面的原因。
如果您正在尋找 $_FILES['error'] 程式碼的說明,請務必閱讀
處理檔案上傳 - 錯誤訊息說明
https://php.dev.org.tw/manual/en/features.file-upload.errors.php
當您使用輸入名稱作為陣列時,重新排序 $_FILES 陣列的一個不錯的技巧是
<?php
function diverse_array($vector) {
$result = array();
foreach($vector as $key1 => $value1)
foreach($value1 as $key2 => $value2)
$result[$key2][$key1] = $value2;
return $result;
}
?>
將轉換此
array(1) {
["upload"]=>array(2) {
["name"]=>array(2) {
[0]=>string(9)"file0.txt"
[1]=>string(9)"file1.txt"
}
["type"]=>array(2) {
[0]=>string(10)"text/plain"
[1]=>string(10)"text/html"
}
}
}
成為
array(1) {
["upload"]=>array(2) {
[0]=>array(2) {
["name"]=>string(9)"file0.txt"
["type"]=>string(10)"text/plain"
},
[1]=>array(2) {
["name"]=>string(9)"file1.txt"
["type"]=>string(10)"text/html"
}
}
}
只需執行
<?php $upload = diverse_array($_FILES["upload"]); ?>
在檢查錯誤碼時,您可能應該檢查程式碼 4。我相信程式碼 4 表示沒有上傳檔案,而且在許多情況下,這是完全可以接受的。
例如,當您有一個包含多個資料項目的表單時,包括檔案和影像上傳,以及其他內容。使用者可能不會因為任何原因新增新的上傳,例如系統中可能已經有先前更新的檔案,而使用者對此感到滿意。
此陣列的格式如下 (假設您的表單有兩個名為「file1」、「file2」等的 input type=file 欄位)
陣列
(
[file1] => 陣列
(
[name] => MyFile.txt (來自瀏覽器,因此請視為受到汙染)
[type] => text/plain (不確定它從哪裡取得這個資訊 - 假設是瀏覽器,因此請視為受到汙染)
[tmp_name] => /tmp/php/php1h4j1o (可能會在您系統上的任何位置,具體取決於您的設定,但使用者無法控制,因此這沒有受到汙染)
[error] => UPLOAD_ERR_OK (= 0)
[size] => 123 (以位元組為單位的大小)
)
[file2] => 陣列
(
[name] => MyFile.jpg
[type] => image/jpeg
[tmp_name] => /tmp/php/php6hst32
[error] => UPLOAD_ERR_OK
[size] => 98174
)
)
我上次檢查時 (確實是有一段時間了),如果您在表單中使用陣列參數 (也就是說,表單名稱以方括號結尾,例如幾個名為「download[file1]」、「download[file2]」等的檔案欄位),則陣列格式會變得...有趣。
陣列
(
[download] => 陣列
(
[name] => 陣列
(
[file1] => MyFile.txt
[file2] => MyFile.jpg
)
[type] => 陣列
(
[file1] => text/plain
[file2] => image/jpeg
)
[tmp_name] => 陣列
(
[file1] => /tmp/php/php1h4j1o
[file2] => /tmp/php/php6hst32
)
[error] => 陣列
(
[file1] => UPLOAD_ERR_OK
[file2] => UPLOAD_ERR_OK
)
[size] => 陣列
(
[file1] => 123
[file2] => 98174
)
)
)
因此,您需要存取 file1 的錯誤參數,例如 $_Files['download']['error']['file1']
這是一個我用來從頁面取得所有傳入檔案的簡單陣列的函式。它基本上只是將 $FILES 陣列扁平化。此函式適用於頁面上的許多檔案輸入,也適用於輸入是否為 '<input type="file[]" multiple>'。請注意,此函式會遺失檔案輸入名稱 (我通常只按類型處理檔案)。
<?php
function incoming_files() {
$files = $_FILES;
$files2 = [];
foreach ($files as $input => $infoArr) {
$filesByInput = [];
foreach ($infoArr as $key => $valueArr) {
if (is_array($valueArr)) { // 檔案輸入 "multiple"
foreach($valueArr as $i=>$value) {
$filesByInput[$i][$key] = $value;
}
}
else { // -> 字串,一般檔案輸入
$filesByInput[] = $infoArr;
break;
}
}
$files2 = array_merge($files2,$filesByInput);
}
$files3 = [];
foreach($files2 as $file) { // 讓我們篩選空白和錯誤
if (!$file['error']) $files3[] = $file;
}
return $files3;
}
$tmpFiles = incoming_files();
?>
將轉換此
陣列
(
[files1] => 陣列
(
[name] => facepalm.jpg
[type] => image/jpeg
[tmp_name] => /tmp/php3zU3t5
[error] => 0
[size] => 31059
)
[files2] => 陣列
(
[name] => 陣列
(
[0] => facepalm2.jpg
[1] => facepalm3.jpg
)
[type] => 陣列
(
[0] => image/jpeg
[1] => image/jpeg
)
[tmp_name] => 陣列
(
[0] => /tmp/phpJutmOS
[1] => /tmp/php9bNI8F
)
[error] => 陣列
(
[0] => 0
[1] => 0
)
[size] => 陣列
(
[0] => 78085
[1] => 61429
)
)
)
變成這樣
陣列
(
[0] => 陣列
(
[name] => facepalm.jpg
[type] => image/jpeg
[tmp_name] => /tmp/php3zU3t5
[error] => 0
[size] => 31059
)
[1] => 陣列
(
[name] => facepalm2.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpJutmOS
[error] => 0
[size] => 78085
)
[2] => 陣列
(
[name] => facepalm3.jpg
[type] => image/jpeg
[tmp_name] => /tmp/php9bNI8F
[error] => 0
[size] => 61429
)
)
關於安全性的注意事項:永遠不要信任 $_FILES["image"]["type"]。它會接收瀏覽器傳送的任何內容,因此不要信任它來判斷圖片類型。我建議使用 finfo_open (https://php.dev.org.tw/manual/en/function.finfo-open.php) 來驗證檔案的 MIME 類型。它會解析檔案中的 MAGIC 並傳回其類型...這是可以信任的 (您也可以在 Unix 上使用 "file" 程式,但我建議永遠不要在您的 PHP 程式碼中進行系統呼叫...那只是自找麻煩)。
檢查 $_FILES 是否為空的最佳方法是檢查索引 0 的名稱是否已設定。
<?php
if ($_FILES['fieldname']['name'][0] != ""){
//程式碼寫在這裡!
}
?>
錯誤代碼會在 $_FILES['userfile']['error'] 中回傳。
■UPLOAD_ERROR_OK,值為 0,表示沒有發生錯誤。
■ UPLOAD_ERR_INI_SIZE,值為 1,表示上傳檔案的大小超過了
在您的 php.ini 檔案中使用 upload_max_filesize 指令指定的最大值。
■ UPLOAD_ERR_FORM_SIZE,值為 2,表示上傳檔案的大小超過了
在 HTML 表單的 MAX_FILE_SIZE 元素中指定的最大值。
■ UPLOAD_ERR_PARTIAL,值為 3,表示檔案只上傳了一部分。
■ UPLOAD_ERR_NO_FILE,值為 4,表示沒有上傳任何檔案。
■ UPLOAD_ERR_NO_TMP_DIR,值為 6,表示在
php.ini 中沒有指定暫存目錄。
■ UPLOAD_ERR_CANT_WRITE,值為 7,表示寫入檔案到磁碟失敗。
■ UPLOAD_ERR_EXTENSION,值為 8,表示 PHP 擴充功能停止了檔案上傳
程序。
對於快速除錯 (例如 var_dump($_FILES);),這些是錯誤常數的值。顯然,不要在實際程式碼中使用這些值進行比較。
UPLOAD_ERR_OK: 0
UPLOAD_ERR_INI_SIZE: 1
UPLOAD_ERR_FORM_SIZE: 2
UPLOAD_ERR_NO_TMP_DIR: 6
UPLOAD_ERR_CANT_WRITE: 7
UPLOAD_ERR_EXTENSION: 8
UPLOAD_ERR_PARTIAL: 3
提交後,PHP 中會出現非典型的陣列。我寫了一個小函式來將其重新轉換為熟悉的樣子。
<?php
function multiple(array $_files, $top = TRUE)
{
$files = array();
foreach($_files as $name=>$file){
if($top) $sub_name = $file['name'];
else $sub_name = $name;
if(is_array($sub_name)){
foreach(array_keys($sub_name) as $key){
$files[$name][$key] = array(
'name' => $file['name'][$key],
'type' => $file['type'][$key],
'tmp_name' => $file['tmp_name'][$key],
'error' => $file['error'][$key],
'size' => $file['size'][$key],
);
$files[$name] = multiple($files[$name], FALSE);
}
}else{
$files[$name] = $file;
}
}
return $files;
}
print_r($_FILES);
/*
陣列
(
[image] => 陣列
(
[name] => 陣列
(
[0] => 400.png
)
[type] => 陣列
(
[0] => image/png
)
[tmp_name] => 陣列
(
[0] => /tmp/php5Wx0aJ
)
[error] => 陣列
(
[0] => 0
)
[size] => 陣列
(
[0] => 15726
)
)
)
*/
$files = multiple($_FILES);
print_r($files);
/*
陣列
(
[image] => 陣列
(
[0] => 陣列
(
[name] => 400.png
[type] => image/png
[tmp_name] => /tmp/php5Wx0aJ
[error] => 0
[size] => 15726
)
)
)
*/
?>
如果 $_FILES 為空,即使上傳檔案時也一樣,請嘗試將 enctype="multipart/form-data" 新增至表單標籤,並確保您已開啟檔案上傳功能。
不知為何,當我嘗試檢查 $_FILES['myVarName'] 是否為 empty() 或 !isset() 或 array_key_exists() 時,它總是回傳該檔案確實存在於超全域變數中,即使沒有上傳任何內容。
我懷疑這是否是 enctype="multipart/form-data" 的結果。
總之,我透過檢查 $_FILES['myVarName']['size'] > 0 來解決我的問題