PHP文件输入数组命名与其他输入不同


PHP file input array naming is not like other inputs

我正在用PHP实现一个多用途的html表单发布代码,该代码能够发布对象图结构

因此,我创建了一些命名规则,并基于它们在服务器端解析索引

其中一条规则是这样的:

<input name="myModels[children[0]]" type="text" />

当然,上面的命名稍微缩短了一点,以便于切中要害

当我从检索到它们时,这种命名非常有效

$_POST

但是当我在文件输入中使用它时,它们永远不会出现在$_file全局数组中和

print_r($_FILES);

是空的

根据文件上传php手册

PHP支持HTML数组功能,甚至支持文件。

那为什么呢?为什么这种类型的命名([]内部的[])适用于POSTED数据,但不适用于文件数据。

请注意,上传文件本身没有问题
即使使用数组,上传也是可行的。即使使用具有键索引的数组。

我想弄清楚的是:

<form action="/Test/uploadTest.php" method="post" enctype="multipart/form-data" >
    File1 <input name="myModels[postedFiles[0]]" type="file" /></br>
    File2 <input name="myModels[postedFiles[1]]" type="file" /></br>
    <input type="submit" value="post" />
</form> 

在uploadTest.php 中的服务器上

print_r($_FILES);

是空的

我的PHP版本有点旧,是PHP 5.3.6-13。你认为这是我的PHP版本的问题吗?还是在新版本的PHP中也有一些bug

提前谢谢。

解决方案:@tozer83和@alvaro提供的答案都很有帮助。现在,事实证明,多部分表单在处理非标量索引和试图利用带有文件输入的html数组的优势来创建用于创建复杂对象图的表达式方面有一些不同,就像其他语言中的其他框架一样,这在PHP中是行不通的。应该忽略html数组或使用括号等其他文字来解决此问题。很难决定应该点击哪一个复选标记!考虑到@alvoro已经获得了这么高的排名,我决定选择@tozer83的答案,因为他首先回答并给出了解决方案。但@alvaro的回答很详细,也很有帮助。所以我+1他的答案。

首先(只是为了澄清)PHP不允许非标量值作为数组键。事实上,只能使用字符串和整数。因此,没有一种语言结构可以容纳像myModels[postedFiles[0]]这样的东西。关于HTML数组的文档并没有真正说明当不可解析的字段名出现时会发生什么

当我们把它推到极限时会发生什么?显然,行为是不同的,这取决于我们谈论的超全球。在$_POST中,PHP尽最大努力创建数组:

<input name="good[array][0]" type="text">
<input name="myModels[children[0]]" type="text">
array(2) {
  ["good"]=>
  array(1) {
    ["array"]=>
    array(1) {
      [0]=>
      string(0) ""
    }
  }
  ["myModels"]=>
  array(1) {
    ["children[0"]=>
    string(0) ""
  }
}

然而,在$_FILES中,无效字段会从数组中省略:

<input name="good[file][0]" type="file">
<input name="myModels[postedFiles[0]]" type="file">
array(1) {
  ["good"]=>
  array(5) {
    ["name"]=>
    array(1) {
      ["file"]=>
      array(1) {
        [0]=>
        string(0) ""
      }
    }
    ["type"]=>
    array(1) {
      ["file"]=>
      array(1) {
        [0]=>
        string(0) ""
      }
    }
    ["tmp_name"]=>
    array(1) {
      ["file"]=>
      array(1) {
        [0]=>
        string(0) ""
      }
    }
    ["error"]=>
    array(1) {
      ["file"]=>
      array(1) {
        [0]=>
        int(4)
      }
    }
    ["size"]=>
    array(1) {
      ["file"]=>
      array(1) {
        [0]=>
        int(0)
      }
    }
  }
}

由于我们试图获得一个物理上不可能的结构,并且文件没有明确说明应该发生什么,我们处于未定义行为的领域:我们既不能抱怨也不能依赖它。

常规的post表单允许我们编写自己的解析器:,这也没有什么价值

var_dump(file_get_contents('php://input'));
string(111) "good%5Barray%5D%5B0%5D=&myModels%5Bchildren%5B0%5D%5D=&good%5Bfile%5D%5B0%5D=&myModels%5BpostedFiles%5B0%5D%5D="

但不是多部分/表单数据(又称文件)。

为什么会出现这种明显的差异?我的猜测是,这是由于$_FILES超全局的特殊结构(IMHO,一种为时已晚的错误设计)。当使用简单的名称时,你会在每片叶子的顶部获得五个自动键:

Array
(
    [one] => Array
        (
            [name] => 
            [type] => 
            [tmp_name] => 
            [error] => 4
            [size] => 0
        )
    [two] => Array
        (
            [name] => 
            [type] => 
            [tmp_name] => 
            [error] => 4
            [size] => 0
        )
)

只要你使用方括号,结构就会完全改变:

Array
(
    [one] => Array
        (
            [name] => Array
                (
                    [0] => 
                )
            [type] => Array
                (
                    [0] => 
                )
            [tmp_name] => Array
                (
                    [0] => 
                )
            [error] => Array
                (
                    [0] => 4
                )
            [size] => Array
                (
                    [0] => 0
                )
        )
    [two] => Array
        (
            [name] => Array
                (
                    [0] => 
                )
            [type] => Array
                (
                    [0] => 
                )
            [tmp_name] => Array
                (
                    [0] => 
                )
            [error] => Array
                (
                    [0] => 4
                )
            [size] => Array
                (
                    [0] => 0
                )
        )
)

这表明$_POST$_FILES中的内部逻辑完全不同,因此在无效输入上看到不同的解决方案并不奇怪。

我试图制作相同的表单,但做了一些修改。

<form action="uploadTest.php" method="post" enctype="multipart/form-data" >
    File1 <input name="myModels[postedFiles(0)]" type="file" /></br>
    File2 <input name="myModels[postedFiles(1)]" type="file" /></br>
    <input type="submit" value="post" />
</form> 

尝试上传文件时的print_r($_FILES)结果:

Array ( [myModels] => Array ( [name] => Array ( [postedFiles(0)] => file1.txt [postedFiles(1)] => file2.txt ) [type] => Array ( [postedFiles(0)] => text/plain [postedFiles(1)] => text/plain ) [tmp_name] => Array ( [postedFiles(0)] => /tmp/phpiHJBb1 [postedFiles(1)] => /tmp/phpSFh4J0 ) [error] => Array ( [postedFiles(0)] => 0 [postedFiles(1)] => 0 ) [size] => Array ( [postedFiles(0)] => 4 [postedFiles(1)] => 4 ) ) )

请参阅此处的PHP手册:https://secure.php.net/manual/en/features.file-upload.post-method.php查看示例#3以上传一组文件。

但是,如果文件太大,这似乎不起作用,这将在php.ini中通过upload_max_filesize甚至post_max_size来指定。