POST-ing HTMLFormElements as Array Keep DOM Order Accross Br



我正在POST三个具有PHP数组命名约定的HTMLinput元素,即name="name[]"(三个inputs具有不同的名称"A[]"、"B[]"one_answers"C[]")。input元素是<td>元素的子元素,其中有7到1001个<td>元素,这意味着每个<td>有3倍于input元素,即21到3003。布局类似于电子表格,例如

<table>
<--! ... -->
<tbody>
<tr>
<td>
<input type="text" name="A[]" placeholder="A1">
<input type="hidden" name="B[]" value="A1">
<input type="hidden" name="C[]" value="2021-10-03">
</td>
<td>
<input type="text" name="A[]" placeholder="B1">
<input type="hidden" name="B[]" value="B1">
<input type="hidden" name="C[]" value="2021-10-04">
</td>
<--! ... -->
</tr>
<--! ... -->
</tbody>
<--! ... -->

当我发布它们时,我注意到服务器端的每个input'数组键都符合input元素在HTMLFormElement中出现的顺序

我想知道的是数组键在浏览器中的顺序是真的吗

我在HTML规范中找不到任何内容,但PHP手册在将input名称表示为name[]:时给出了以下注释

在HTML中指定数组键是可选的。如果不指定键,数组将按元素在表单中的显示顺序填充。我们的第一个示例将包含键0、1、2和3。

谢谢你的问题,很有趣,但我有问题需要具体回答。这是因为这取决于实现,并且它可以(或者正如我们所看到的,至少可以)在不同的浏览器之间有所不同。

对于PHP部分,这是在PHPs源代码中编码的,因此是定义的,但这只是一个方面,我有根据的猜测(没有研究过源代码)是它取决于输入顺序

这就是我的理解:给定浏览器从成功的控件构建表单数据集,然后对其进行编码。对于HTML表单(摘录)中的PHP数组键(您感兴趣的顺序)示例:

<form method="post">
...
<td>
<input type="text" name="A[]" placeholder="A1">
<input type="hidden" name="B[]" value="A1">
<input type="hidden" name="C[]" value="2021-10-03">
</td>
<td>
<input type="text" name="A[]" placeholder="B1">
<input type="hidden" name="B[]" value="B1">
<input type="hidden" name="C[]" value="2021-10-04">
</td>
...
</form>

我假设要构建表单数据集的输入元素的文档顺序。IIRC的问题是,在HTML中没有文档顺序的规范。DOM中有DOM,但据我所知,浏览器一定没有DOM。内部没有DOM浏览器(或一些具有类似语义的结构)可能很愚蠢,但HTML规范中没有要求有DOM:据我所知,DOM是特定于Javascript的,浏览器不能支持任何客户端脚本。


注意:HTML生活标准支持这种解释(截至2021-10-03年)。它与表单数据编码中的DOM无关,而是具有树顺序,其语义与DOM文档顺序相似。正是从中获得输入元素的列表,用于识别构建和编码表单数据的成功控件所有列表都有有序的序列(从第一个到最后一个,添加附加项),初始化为空,并从头到尾遍历。因此,该序列被保留,包括在编码序列化程序的编码中,该编码成为PHP SAPI解析的输入。

这证实了输入顺序总是相同的观察结果。如果不是(你好奇的部分),你可以把它当作一个缺陷。您的标准表单输入验证无论如何都应该处理这种情况,因为请求中的任何表单数据都可能在其他地方组成(例如,不同的表单,表单提交没有相同的来源策略),因此需要验证。


考虑到有DOM支持,并且在创建表单数据集时也在内部使用考虑到在构建数据集时成功的输入是按文档顺序处理的,因此按自上而下的顺序创建以下数据集(每行一个控件名称/当前值对):

A[]: A1
B[]: A1
C[]: 2021-10-03
A[]: B1
B[]: B1
C[]: 2021-10-04

如果是该数据集的编码结果(在HTML 4.01规范中没有进一步指定顺序)。同样,实现它与处理顺序不同会有点违反直觉,但如果在处理顺序中,则将输入顺序定义为PHP SAPI接收此数据(HTTP请求体)并从中形成$_POST数组。

接下来是以下内容(至少我是如何向自己解释的,没有在来源中得到验证):

  1. $_POST数组初始化为空
  2. 第一个控件名称为A[]
  3. PHP";实现";数组访问括号CCD_ 16并且在这些括号内没有给出索引或关键字
  4. 因此,数组的填充与PHP代码中的类似:$_POST['A'][] = 'A1';(比较:array_push())
  5. 这些步骤2.-4.为每个名称/值对完成

现在这并不能具体回答您的问题。但是,如果您是因为想在stone中设置索引而提出要求的(除了任何顺序),则应该可以在HTML表单控件名称中提供这些索引,这可能就是您想要的:

<form method="post">
...
<td>
<input type="text" name="A[0]" placeholder="A1">
<input type="hidden" name="B[0]" value="A1">
<input type="hidden" name="C[0]" value="2021-10-03">
</td>
<td>
<input type="text" name="A[1]" placeholder="B1">
<input type="hidden" name="B[1]" value="B1">
<input type="hidden" name="C[1]" value="2021-10-04">
</td>
...
</form>

然后,至少在通过$_POST访问的级别上,键被定义为HTML标准需要保留的控件名称。它们有你想要的名字,因为你可以通过数字索引重新创建订单。


如果你关心行,你所需要做的就是将那些";命名为";部分(因为PHP正在处理[...]数组部分)到它们的索引:

// required input
$input = $_POST;
// define structure of result data
$fields = ['A' => null, 'B' => null, 'C' => null];
$count = 2;
// initialize the result
$result = array_fill(0, $count, $fields);
// map $input to $result
foreach (array_keys($result) as $index) {
foreach ($fields as $name => $default) {
$result[$index][$name] = $_POST[$name][$index] ?? $result[$index][$name];
}
}

这样的部分也是验证输入是否完整的好地方。生成的$result(选择最适合您的情况的名称)也更好地映射到数据库字段(例如,当您从结构中生成输入时,请在表单中使用A、B、C…,然后使用相同的结构将它们映射回数据库(或应用程序内部实体/属性名称)。

如果您意识到订单突然变得脆弱,情况尤其如此——即使HTTP是无状态的,您也可以使表单创建/提交/数据处理成为一个更独特的事务。至少在数据级别上更加明显。


这给我带来了另一个改进/变体,即在编写表单的HTML时,数据已按处理顺序在$_POST中。它不会省去所需的验证步骤,但这可以在PHP:中完成

<td>
<input type="text" name="set[0][D]" placeholder="A1">
<input type="hidden" name="set[0][E]" value="A1">
<input type="hidden" name="set[0][F]" value="2021-10-05">
</td>
<td>
<input type="text" name="set[1][D]" placeholder="B1">
<input type="hidden" name="set[1][E]" value="B1">
<input type="hidden" name="set[1][F]" value="2021-10-06">
</td>

那么$_POST['set']已经包含有序数组中的形式数据,并且不需要换位,并且为了映射顺序,ksort可能已经足够了:

ksort($_POST['set']);

因此,这有助于立即处理表单数据(如果输入元素的顺序正确,则数字索引也可以省略,不需要ksort(),PHP将负责处理)。

甚至可以省略名字,但这可能没有用,因为其他表单字段与集合无关:

<td>
<input type="text" name="0[G]" placeholder="A1">
<input type="hidden" name="0[H]" value="A1">
<input type="hidden" name="0[I]" value="2021-10-07">
</td>
<td>
<input type="text" name="1[G]" placeholder="B1">
<input type="hidden" name="1[H]" value="B1">
<input type="hidden" name="1[I]" value="2021-10-08">
</td>

使$_POST成为数组的数字索引(按未定义的顺序)数组。

最新更新