参见 https://php.net/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.net/manual/en/features.file-upload.post-method.php 以了解 $_FILES 数组的文档,这就是我一开始来这个页面的原因。
如果您正在寻找 $_FILES['error'] 错误代码解释,请务必阅读
处理文件上传 - 错误消息解释
https://php.net/manual/en/features.file-upload.errors.php
在 $_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 扩展阻止了文件上传进程。
■ UPLOAD_ERR_EXTENSION,值 8,表示 PHP 扩展阻止了文件上传进程。
■ UPLOAD_ERR_EXTENSION,值 8,表示 PHP 扩展阻止了文件上传进程。
■ UPLOAD_ERR_EXTENSION,值 8,表示 PHP 扩展阻止了文件上传进程。
■ UPLOAD_ERR_EXTENSION,值 8,表示 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"]); ?>
此数组的格式为(假设您的表单有两个名为“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]”等的 file 字段一样),那么数组格式就变得......有趣。
数组
(
[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["image"]["type"]。它接收浏览器发送的任何内容,因此不要将其用作图像类型。我建议使用 finfo_open (https://php.net/manual/en/function.finfo-open.php) 来验证文件的 MIME 类型。它将解析文件中的 MAGIC 并返回其类型......这是可以信任的(您也可以使用 Unix 上的“file”程序,但我建议不要使用 PHP 代码进行任何系统调用......这只会导致问题)。
在检查错误代码时,您可能应该检查代码 4。我认为代码 4 表示没有上传文件,在很多情况下这是完全可以的。
例如,当您有一个包含多个数据项的表单,包括文件和图像上传,以及其他任何内容时。用户可能没有添加新上传,原因有很多,例如可能已经有一个文件在系统中,来自早期的更新,并且用户对该文件感到满意。
以下是我用来获取页面所有传入文件的简单数组的函数。它基本上只是将 $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 是否为空的最佳方法是检查索引 0 的名称是否已设置。
<?php
if ($_FILES['fieldname']['name'][0] != ""){
//代码在此处!
}
?>
用于快速调试(例如 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
如果 $_FILES 为空,即使在上传时,也尝试将 enctype="multipart/form-data" 添加到表单标签,并确保已启用文件上传。
提交后,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 数组,因此
function getRequestFiles()
{
$result = array();
if (is_array($_FILES)) {
foreach($_FILES as $name => $fileArray) {
$row = array();
foreach ($fileArray as $key => &$data) {
findNoArrayElementAndReplace($data, $key);
$row = array_merge_recursive($row, $data);
}
$result[$name] = $row;
}
}
return $result;
}
function findNoArrayElementAndReplace(&$array, $key)
{
if (is_array($array)) {
foreach ($array as &$item) {
findNoArrayElementAndReplace($item, $key);
}
} else {
$array = array(
$key => $array
);
}
}
出于某种原因,当我尝试检查 $_FILES['myVarName'] 是否为空() 或 !isset() 或 array_key_exists() 时,它总是返回文件确实存在于超级全局变量中,即使没有上传任何内容。
我想知道这是否是 enctype="multipart/form-data" 的结果。
无论如何,我通过检查以确保 $_FILES['myVarName']['size'] > 0 来解决我的问题。
过去,您可以无条件地调用 $_FILES['profile_pic'],而无需担心 PHP 会抛出“未定义的索引:profile_pic”错误(只要发布页面的文件输入存在(例如 <input type="file" name="profile_pic" />))。 这种情况无论最终用户是否实际上传了文件都是如此。 如今,由于有太多人通过 iPad 浏览网络,因此您必须在调用它之前明确检查输入 isset($_FILES['profile_pic']),否则您将收到上述错误消息。 这是因为运行 Safari 的 iOS 设备会禁用文件输入,从而导致它们被视为不存在。 该更新您的脚本!
-john
对于下载[文件1]、下载[文件2]、...、下载[文件N] 的情况,请尝试以下方法
<?php
/**
*
* @param array $arrayForFill
* @param string $currentKey
* @param mixed $currentMixedValue
* @param string $fileDescriptionParam (name, type, tmp_name, error 或 size)
* @return void
*/
function rRestructuringFilesArray(&$arrayForFill, $currentKey, $currentMixedValue, $fileDescriptionParam)
{
if (is_array($currentMixedValue)) {
foreach ($currentMixedValue as $nameKey => $mixedValue) {
rRestructuringFilesArray($arrayForFill[$currentKey],
$nameKey,
$mixedValue,
$fileDescriptionParam);
}
} else {
$arrayForFill[$currentKey][$fileDescriptionParam] = $currentMixedValue;
}
}
$arrayForFill = array();
foreach ($_FILES as $firstNameKey => $arFileDescriptions) {
foreach ($arFileDescriptions as $fileDescriptionParam => $mixedValue) {
rRestructuringFilesArray($arrayForFill,
$firstNameKey,
$_FILES[$firstNameKey][$fileDescriptionParam],
$fileDescriptionParam);
}
}
$_FILES = $arrayForFill;
?>
您可以通过这种方式检查错误索引
<?php
$errorIndex = $_FILES["file"]["error"];
if ($errorIndex > 0) {
die('We have a error. Try Again.');
}
processFile();
?>
附件中的“new FILES_flattened”类将 $_FILES 数组扁平化,适用于任何组合的“单个”文件、带有给定索引 [i] 的多文件数组或带有 [] 索引的多文件数组,甚至多级多文件数组 [i][j]...[n]。
在扁平化数组中添加一个元素“pos”,它将为多文件数组的每个文件保存“节点路径”,例如'pos' => [ i, j ],这样就可以用于在数据库数组中正确放置文件,或用于创建追加每个索引级别的自动名称。
最重要的是,HTML 输入的“name”属性和其他所有信息保持完整。
HTML <form> 代码片段
<input type="hidden" name="MAX_FILE_SIZE" value="2500000" title="每个文件允许的字节数。" />
<input type="file" name="pictures[4]" accept="image/*" />
<input type="file" name="thumb" accept="image/*" />
<input type="file" name="pictures[]" accept="image/*" />
<input type="file" name="pictures[10][5]" accept="image/*" />
<input type="file" name="pictures[17]" accept="image/*" />
结果
一个扁平化的数组,每个 <input> 字段一个元素,每个元素都具有以下结构
...
'pictures' => array (size=6)
'name' => 'ClientFilename.jpg'
'type' => 'image/jpeg' (
'tmp_name' => '...\php8D2C.tmp'
'error' => 0
'size' => 1274994
'pos' => array (size=2)
0 => 10
1 => 5
...
只需要一个简单的 foreach 循环
<?php
foreach( new RecursiveIteratorIterator( new FILES_flattened ) as $key => $data ) {
var_dump( $key, $data );
// 以下是使用“pos”元素生成自动名称的方法,例如“picture[10][5]”
// 包含“节点路径”
echo $key.( empty( $data[ 'pos' ] ) ? '' : '['. implode( '][', $data[ 'pos' ] ) . ']' );
}
这是一个将西里尔字母和变音字符作为文件名上传时转换为所需编码的解决方案。我一直在寻找它,但找不到。因此,我发布了这个。就像这样
$value = mb_convert_encoding($value, "UTF-8");
我将 $_FILES 数组规范化为
[doc] => Array
(
[0] => 数组
(
[name] => testfile.txt
[type] => application/octet-stream
[tmp_name] => /tmp/php6wHXmC
[error] => 0
[size] => 4
)
[affe] => Array
(
[name] => testfile.txt
[type] => application/octet-stream
[tmp_name] => /tmp/phpfiHK2e
[error] => 0
[size] => 4
)
)
<?php
function getFiles() {
$result = array();
foreach($_FILES as $name => $fileArray) {
if (is_array($fileArray['name'])) {
foreach ($fileArray as $attrib => $list) {
foreach ($list as $index => $value) {
$result[$name][$index][$attrib]=$value;
}
}
} else {
$result[$name][] = $fileArray;
}
}
return $result;
}
?>
因此,即使你发布一个或多个文件,你始终拥有相同的结构
<?php
// 单个文件
$request->addFileFromLocalFilePath('doc','testfile.txt');
// 多个文件
$request->addFileFromLocalFilePath('doc[0]','testfile.txt');
$request->addFileFromLocalFilePath('doc[affe]','testfile.txt');
foreach ($request->getFiles() as $fieldName => $files) {
foreach ($files as $index => $fileArray) {
echo $fileArray['tmp_name'];
}
}
?>
我编写了这个函数来重构深度嵌套的 $_FILES 数组,以便将每个文件的参数分组在一起。
function restructure_files(array $input)
{
$output = [];
foreach ($input as $name => $array) {
foreach ($array as $field => $value) {
$pointer = &$output[$name];
if (!is_array($value)) {
$pointer[$field] = $value;
continue;
}
$stack = [&$pointer];
$iterator = new \RecursiveIteratorIterator(
new \RecursiveArrayIterator($value),
\RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $key => $value) {
array_splice($stack, $iterator->getDepth() + 1);
$pointer = &$stack[count($stack) - 1];
$pointer = &$pointer[$key];
$stack[] = &$pointer;
if (!$iterator->hasChildren()) {
$pointer[$field] = $value;
}
}
}
}
return $output;
}
将这个
array (size=2)
'one' =>
array (size=5)
'name' =>
array (size=1)
'inner' =>
array (size=2)
11 => string 'DM4C2738.jpg' (length=12)
5 => string 'DM4C2760.jpg' (length=12)
'type' =>
array (size=1)
'inner' =>
array (size=2)
11 => string 'image/jpeg' (length=10)
5 => string 'image/jpeg' (length=10)
'tmp_name' =>
array (size=1)
'inner' =>
array (size=2)
11 => string '/private/var/tmp/phploOZRb' (length=26)
5 => string '/private/var/tmp/phpsFkmIh' (length=26)
'error' =>
array (size=1)
'inner' =>
array (size=2)
11 => int 0
5 => int 0
'size' =>
array (size=1)
'inner' =>
array (size=2)
11 => int 1031601
5 => int 674697
'two' =>
array (size=5)
'name' => string '9ncYySC.jpg' (length=11)
'type' => string 'image/jpeg' (length=10)
'tmp_name' => string '/private/var/tmp/phpuG99X9' (length=26)
'error' => int 0
'size' => int 882422
转换成这个
array (size=2)
'one' =>
array (size=1)
'inner' =>
array (size=2)
11 =>
array (size=5)
'name' => string 'DM4C2738.jpg' (length=12)
'type' => string 'image/jpeg' (length=10)
'tmp_name' => string '/private/var/tmp/phploOZRb' (length=26)
'error' => int 0
'size' => int 1031601
5 =>
array (size=5)
'name' => string 'DM4C2760.jpg' (length=12)
'type' => string 'image/jpeg' (length=10)
'tmp_name' => string '/private/var/tmp/phpsFkmIh' (length=26)
'error' => int 0
'size' => int 674697
'two' =>
array (size=5)
'name' => string '9ncYySC.jpg' (length=11)
'type' => string 'image/jpeg' (length=10)
'tmp_name' => string '/private/var/tmp/phpuG99X9' (length=26)
'error' => int 0
'size' => int 882422
我意识到这里有很多关于重新格式化 php $_FILES 数组的帖子,但它们不能处理所有情况。这个处理了单个情况、多个文件的情况,甚至提交多个文件数组。这样,无论如何,在我接触文件数组之前,我都会调用这个函数,不管它是什么
<?php
/**
* 这是为了修复 PHP 在文件输入具有 PHP 数组名称时创建的奇怪文件数组:
* 例如:<file name="model[column]" value='file1'> <file name="model[column2][]" value='file2'>
* 变为:$_FILES['model']['name'][column] = file1_name.xxx
* $_FILES['model']['name'][column2][0] = file2_name.xxx
*
* 这将它更改为:
* $files['model'][column]['name'] = file1_name.xxx
* $files['model'][column2][0]['name'] = file2_name.xxx
*
* 这样,文件数据就会按预期分组,就像在非数组类型的 name 属性中那样。
*/
static public function multi_file_fix($files = null)
{
if ($files == null) {
$files = (is_array($_FILES)) ? $_FILES : array();
}
// 确保存在文件,并查看第一个项目是否也是数组
$new_files = array();
foreach ($files as $name => $attributes) {
if (is_array(reset($attributes))) { // 检查第一个项目
foreach ($attributes as $attribute => $item) { // 数组文件提交,例如 name="model[file]"
foreach ($item as $key => $value) {
if (is_array($value)) {
foreach ($value as $key2 => $sub_val) { // 多维数组文件提交,例如 name="model[file][]"
$new_files[$name][$key][$key2][$attribute] = $sub_val;
}
} else {
$new_files[$name][$key][$attribute] = $value;
}
}
}
} else { // 常规文件提交,例如 name="file"
$new_files[$name] = $attributes;
}
}
return $new_files;
}
// 用法:
$files = multi_file_fix($_FILES);
?>
我刚花了很长时间调试我们的一个应用程序在新网络托管上的奇怪行为。在一个页面上,我们有 30 个文件输入,用于上传到服务器。问题是实际上只上传了 20 个。
我发现 php.ini 中有一个选项 max_file_uploads,它默认限制 $_FILES 的最大大小为 20。
如果安装了 suhosin 扩展,它也有自己的选项限制相同内容为 25(php.ini 中的 suhosin.upload.max_uploads)。
其他人已经发布了关于 $_FILES 数组如何根据 HTML 输入是单选类型还是多选类型以不同方式组织数据的帖子,因此这似乎是一个常见的问题。如果出于某种原因需要混合使用这些类型,或者不确定从多选输入中会收到多少文件,这是一种非常有用的重新组织 $_FILES 数组的方法。此外,与之前的帖子不同,新数组的格式(即键和值的个数)是一致的。
<?php
// 重新组织 $_FILES 数组信息
$files = Array ();
$i = 0;
// 从 $_FILES 数组中的所有输入开始
foreach ($_FILES as $input)
{
$j = 0;
foreach ($input as $property => $value)
{
if (is_array($value))
{
$j = count($value); // 迭代次数
for ($k = 0; $k < $j; ++$k)
{
$files[$i + $k][$property] = $value[$k];
}
}
else
{
$j = 1;
$files[$i][$property] = $value;
}
}
$i += $j;
}
?>
结果将类似于以下内容
$files = Array (
[0] => Array (
[name] => ''
[type] => ''
[tmp_name] => ''
[error] => 0
[size] => 0
)
)
如前所述,您应该检查上传的错误索引。
以下示例表明您有一个名为“image”的文件字段。
<?php
if($_FILES['image']['error'] == 0){
// 成功 - 将上传的文件移动到此处并处理内容
}else{
// '上传文件时出现错误' 内容在此处....
}
?>
.htaccess 文件中存在修改 URL 的 URL 重写模式有时会影响 $_FILES。即使 PHP 页面加载并正常工作,由于此原因,此变量可能无法正常工作。因此,如果您将“www.example.com”重写为“example.com”,请确保在将 POST 发送到 PHP 页面时使用后者。我仍然不确定为什么会发生这种情况,但值得在此处注意,以便其他人不会浪费时间追逐幽灵。
如果您正在上传多个文件,并且将文件输入命名为“upload[]”,那么 $_FILES 数组将与下面发布的 var_dump 不同。我认为我会发布它是什么样的,因为它曾经(并且仍然)给我带来头痛!
array(1) {
["upload"]=>array(5) {
["name"]=>array(3) {
[0]=>string(9)"file0.txt"
[1]=>string(9)"file1.txt"
[2]=>string(9)"file2.txt"
}
["type"]=>array(3) {
[0]=>string(10)"text/plain"
[1]=>string(10)"text/plain"
[2]=>string(10)"text/plain"
}
["tmp_name"]=>array(3) {
[0]=>string(14)"/tmp/blablabla"
[1]=>string(14)"/tmp/phpyzZxta"
[2]=>string(14)"/tmp/phpn3nopO"
}
["error"]=>array(3) {
[0]=>int(0)
[1]=>int(0)
[2]=>int(0)
}
["size"]=>array(3) {
[0]=>int(0)
[1]=>int(0)
[2]=>int(0)
}
}
}
(我以为数组应该是 upload[index][name],但事实并非如此。)
这是我的 $_FILES 重新排列版本。与这里其他代码不同,它在任何 $_FILES 深度上都能正常工作。
<?php
if (!empty($_FILES)) {
function rearrange_files_array(array $array) {
foreach ($array as &$value) {
$_array = array();
foreach ($value as $prop => $propval) {
if (is_array($propval)) {
array_walk_recursive($propval, function(&$item, $key, $value) use($prop) {
$item = array($prop => $item);
}, $value);
$_array = array_replace_recursive($_array, $propval);
} else {
$_array[$prop] = $propval;
}
}
$value = $_array;
}
return $array;
}
echo '<pre>'.print_r(rearrange_files_array($_FILES), true).'</pre>';
}
?>
<form method="post" enctype="multipart/form-data" style="clear: both;">
<h3>upload1</h3>
<div><label>new0</label><input type="file" name="upload1[new][]" /></div>
<div><label>new1</label><input type="file" name="upload1[new][]" /></div>
<div><label>update.id11</label><input type="file" name="upload1[update][id11]" /></div>
<div><label>update.id12</label><input type="file" name="upload1[update][id12]" /></div>
<hr />
<h3>upload2</h3>
<div><label>new0</label><input type="file" name="upload2[]" /></div>
<div><label>new1</label><input type="file" name="upload2[]" /></div>
<div><label>update.id21</label><input type="file" name="upload2[id21]" /></div>
<div><label>update.id22</label><input type="file" name="upload2[id22]" /></div>
<hr />
<div><label>upload3</label><input type="file" name="upload3" /></div>
<input type="submit" value="go" />
</form>
提交空表单后的输出
数组
(
[upload1] => Array
(
[new] => Array
(
[0] => 数组
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
[1] => 数组
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
[update] => Array
(
[id11] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
[id12] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
)
[upload2] => Array
(
[0] => 数组
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
[1] => 数组
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
[id21] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
[id22] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
[upload3] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
我花了 3 个小时试图找出为什么当我上传多个文件时 $_FILES 返回空,我注意到只有当我选择超过 3M 的文件时才会出现这种情况,所以我认为这与 MAX_UPLOAD_SIZE 有关,但令我惊讶的是它默认设置为 20M,这非常令人困惑。后来我发现问题出在 POST_MAX_SIZE 上,它设置为 3M,因此不仅 MAX_UPLOAD_SIZE 负责,这就是为什么我想知道为什么没有显示原因的错误消息。
仅上传一个文件,我的版本,它检查文件是否已上传。
function processForm($messages) {
if ($_FILES['file']["error"] == UPLOAD_ERR_OK ) {
if($_FILES['file']['type'] != "text/csv" && $_FILES['file']['type'] != "application/vnd.ms-excel") {
$messages->add_error('Wrong format.');
return false;
}
elseif ( !move_uploaded_file( $_FILES['file']["tmp_name"], "files/" .
basename( $_FILES['file']["name"] ) ) ) {
$messages->add_error('Upload failed');
return false;
}
}
else {
$messages->add_error("Something went wrong.");
return false;
}
return true;
}
if (isset($_POST['btnUpload'])) {
if(is_uploaded_file($_FILES['file']['tmp_name'])) {
if (processForm($messages)) {
$fileName = "files/" . basename($_FILES['file']['name']);
parseAndInsert($fileName, $db);
$messages->add_message("Success");
}
}
else {
$messages->add_error('File did not upload');
}
}
function parseAndInsert($fileName, $db) {
$file = fopen($fileName, "r");
while($line = fgetcsv($file, 1000, ";")) {
$db->addGrade(intval($line[0]), intval($line[1]), intval($line[2]));
}
fclose($file);
}
任何级别的数组 <input> 的直接“扁平”访问的综合迭代器,可以任意组合
<?php
foreach( new RecursiveIteratorIterator( new FILES_flattened ) as $key => $data ) {
var_dump( $key, $data );
// 以下是生成包含“节点路径”的自动名称的方法,例如“picture[10][5]”。
echo $key.( empty( $data[ 'pos' ] ) ? '' : '['. implode( '][', $data[ 'pos' ] ) . ']' );
}
class FILES_flattened implements RecursiveIterator
{
protected $list_array;
protected $basename;
protected $current;
public function __construct()
{
$this->list_array = $_FILES;
}
public function rewind(): void
{
if ( false === $current = reset( $this->list_array ) or null === $this->basename = key( $this->list_array ) ) {
$this->current = null;
return;
}
$current[ 'pos' ] = array();
$this->current = $current;
}
public function next(): void
{
if ( false === $current = next( $this->list_array ) or null === $this->basename = key( $this->list_array ) ) {
$this->current = null;
return;
}
$current[ 'pos' ] = array();
$this->current = $current;
}
public function valid(): bool
{
return null !== key( $this->list_array ); // 数组的结尾(包括空数组)。
}
public function hasChildren(): bool
{
return is_array( $this->current[ 'name' ] );
}
public function getChildren(): FILES_nested
{
return new FILES_nested( $this->basename, $this->current );
}
public function current()
{
return $this->current;
}
public function key()
{
return $this->basename;
}
}
class FILES_nested extends FILES_flattened implements RecursiveIterator
{
private $node_array;
private $position;
public function __construct( string $basename, array $node_array )
{
$this->basename = $basename;
$this->list_array = $node_array[ 'name' ];
$this->position = $node_array[ 'pos' ];
unset( $node_array[ 'pos' ] );
$this->node_array = $node_array;
}
public function rewind(): void
{
if ( false === reset( $this->list_array ) or null === $key = key( $this->list_array ) ) {
$this->current = null;
return;
}
$this->current = $this->normalize( $key );
}
public function next(): void
{
if ( false === next( $this->list_array ) or null === $key = key( $this->list_array ) ) {
$this->current = null;
return;
}
$this->current = $this->normalize( $key );
}
private function normalize( $key ): array
{
$normalized = array_combine( array_keys( $this->node_array ), array_column( $this->node_array, $key) );
$position = $this->position;
$position[] = $key;
$normalized[ 'pos' ] = $position;
return $normalized;
}
}
要确定上传是否成功,你应该检查错误是否为 UPLOAD_ERR_OK,而不是检查文件大小。 当没有选择要上传的文件时,$_FILES 中的键仍然存在,但其错误应该等于 UPLOAD_ERR_NO_FILE。
如果你得到 NULL 值并且想查看返回的错误,你可以在你的命令末尾添加 ' 2>&1'。 在 Linux 服务器上,这会将 stderr 重定向到 stdout(因此字符串错误将被输出)。 这可能为我节省了大量时间。