我已经通过 Stack Overflow 寻找答案,但问题仍然没有得到解答。这是我的问题:
我想通过 PHP 将表单中的 48 个 $_POST['textarea'] 值保存到 mySQL 数据库中。
因此数组执行方法由于参数过多而难以处理,
我在这篇文章( PHP Mysql PDO number of bound variables does not match number of tokens )中找到了帮助,它允许我“准备”、“绑定(bind)参数”和“执行”:当时第一个代码已经很大了。但我选择不要太敏感并接受这种不优雅。
- 我的痛苦开始了:从现在开始,我将拥有可变数量(意味着每个用户都有不同的数量)$_POST['things'],并且从那时起循环似乎可能配置每个变量名称(为其处理
htmlspectialchar()
,bindParam()
),我面临这个不方便的问题:我不知道如何生成这些不同的变量名称。
因此我尝试了上面的代码,但我遇到了没有问题的情况。
如何组织代码以创建与我的
$nbr_of_domain
一样多的变量以保存在数据库中变量?还有一个教学问题:我之前已经学会了通过
execute(aray['param'=>$param
绑定(bind)参数...bindParam() 函数做同样的事情吗?那么它是否只对一定数量的参数有用?
PS:最后你会发现html <form>
代码(可能粗略地删除了敏感信息,但主要结构在这里)
public function saveInfos()
{ //Save info from main board into database table user_board_items.
$domain_assig='';
$UM = new UserManager;
if(isset($_SESSION['user_pseudo'])){
$user_id=$UM->getUserId($_SESSION['user_pseudo']);
}
$DB=$this->dbConnect();
$nbr_of_domain=$this->getNumberOfDomains();
//BUILD REQUEST
for($i=1; $i<=$nbr_of_domain;$i++){
if($i<$nbr_of_domain){
$domain_assig .='DM'.$i.'_ST_G=:DM'.$i.'_ST_G,'
.'DM'.$i.'_MT_G=:DM'.$i.'_MT_G,'
.'DM'.$i.'_LT_G=:DM'.$i.'_LT_G,'
.'DM'.$i.'_ST_T=:DM'.$i.'_ST_T,'
.'DM'.$i.'_MT_T=:DM'.$i.'_MT_T,'
.'DM'.$i.'_LT_T=:DM'.$i.'_LT_T,';
}else {
$domain_assig .='DM'.$i.'_ST_G=:DM'.$i.'_ST_G,'
.'DM'.$i.'_MT_G=:DM'.$i.'_MT_G,'
.'DM'.$i.'_LT_G=:DM'.$i.'_LT_G,'
.'DM'.$i.'_ST_T=:DM'.$i.'_ST_T,'
.'DM'.$i.'_MT_T=:DM'.$i.'_MT_T,'
.'DM'.$i.'_LT_T=:DM'.$i.'_LT_T';
}
}
$req = sprintf("UPDATE user_board_items SET %s WHERE user_id=:user_id",$domain_assig);
//PREPARING REQUEST
$saveRequest = $DB->prepare($req);
//PROTECTING PARAMETERS BEFORE BOUNDING
for($i=1; $i<=$nbr_of_domain;$i++){
$saveRequest->bindParam(':DM'.$i.'_ST_G',htmlspecialchars($_POST['DM'.$i.'_ST_G']));
$saveRequest->bindParam(':DM'.$i.'_MT_G',htmlspecialchars($_POST['DM'.$i.'_MT_G']));
$saveRequest->bindParam(':DM'.$i.'_LT_G',htmlspecialchars($_POST['DM'.$i.'_LT_G']));
$saveRequest->bindParam(':DM'.$i.'_ST_T',htmlspecialchars($_POST['DM'.$i.'_ST_T']));
$saveRequest->bindParam(':DM'.$i.'_MT_T',htmlspecialchars($_POST['DM'.$i.'_MT_T']));
$saveRequest->bindParam(':DM'.$i.'_LT_T',htmlspecialchars($_POST['DM'.$i.'_LT_T']));
}
$saveRequest->bindParam(':user_id',$user_id);
$saveRequest->execute();
$saveRequest->closeCursor();
}
对于最勇敢的人来说,这是我旧的工作但严格的代码版本,它不允许变量 number 的变化(如此程序化!:):
public function saveInfos()
{ //Save info from main borad into database table user_board_items
//ini_set('memory_limit', '1024M'); // or you could use 1G
$UM = new UserManager;
if(isset($_SESSION['user_pseudo'])){
$user_id=$UM->getUserId($_SESSION['user_pseudo']);
}
$DB=$this->dbConnect();
$req = "UPDATE
user_board_items
SET
DM1_ST_G=:DM1_ST_G,
DM1_MT_G=:DM1_MT_G,
DM1_LT_G=:DM1_LT_G,
DM1_ST_T=:DM1_ST_T,
DM1_MT_T=:DM1_MT_T,
DM1_LT_T=:DM1_LT_T,
DM2_ST_G=:DM2_ST_G,
DM2_MT_G=:DM2_MT_G,
DM2_LT_G=:DM2_LT_G,
DM2_ST_T=:DM2_ST_T,
DM2_MT_T=:DM2_MT_T,
DM2_LT_T=:DM2_LT_T,
DM3_ST_G=:DM3_ST_G,
DM3_MT_G=:DM3_MT_G,
DM3_LT_G=:DM3_LT_G,
DM3_ST_T=:DM3_ST_T,
DM3_MT_T=:DM3_MT_T,
DM3_LT_T=:DM3_LT_T,
DM4_ST_G=:DM4_ST_G,
DM4_MT_G=:DM4_MT_G,
DM4_LT_G=:DM4_LT_G,
DM4_ST_T=:DM4_ST_T,
DM4_MT_T=:DM4_MT_T,
DM4_LT_T=:DM4_LT_T,
DM5_ST_G=:DM5_ST_G,
DM5_MT_G=:DM5_MT_G,
DM5_LT_G=:DM5_LT_G,
DM5_ST_T=:DM5_ST_T,
DM5_MT_T=:DM5_MT_T,
DM5_LT_T=:DM5_LT_T,
DM6_ST_G=:DM6_ST_G,
DM6_MT_G=:DM6_MT_G,
DM6_LT_G=:DM6_LT_G,
DM6_ST_T=:DM6_ST_T,
DM6_MT_T=:DM6_MT_T,
DM6_LT_T=:DM6_LT_T,
DM7_ST_G=:DM7_ST_G,
DM7_MT_G=:DM7_MT_G,
DM7_LT_G=:DM7_LT_G,
DM7_ST_T=:DM7_ST_T,
DM7_MT_T=:DM7_MT_T,
DM7_LT_T=:DM7_LT_T,
DM8_ST_G=:DM8_ST_G,
DM8_MT_G=:DM8_MT_G,
DM8_LT_G=:DM8_LT_G,
DM8_ST_T=:DM8_ST_T,
DM8_MT_T=:DM8_MT_T,
DM8_LT_T=:DM8_LT_T
WHERE user_id=:user_id";
$saveRequest = $DB->prepare($req);
$DM1_ST_G= htmlspecialchars($_POST['DM1_ST_G']);
$DM1_MT_G= htmlspecialchars($_POST['DM1_MT_G']);
$DM1_LT_G= htmlspecialchars($_POST['DM1_LT_G']);
$DM1_ST_T= htmlspecialchars($_POST['DM1_ST_T']);
$DM1_MT_T= htmlspecialchars($_POST['DM1_MT_T']);
$DM1_LT_T= htmlspecialchars($_POST['DM1_LT_T']);
$DM2_ST_G= htmlspecialchars($_POST['DM2_ST_G']);
$DM2_MT_G= htmlspecialchars($_POST['DM2_MT_G']);
$DM2_LT_G= htmlspecialchars($_POST['DM2_LT_G']);
$DM2_ST_T= htmlspecialchars($_POST['DM2_ST_T']);
$DM2_MT_T= htmlspecialchars($_POST['DM2_MT_T']);
$DM2_LT_T= htmlspecialchars($_POST['DM2_LT_T']);
$DM3_ST_G= htmlspecialchars($_POST['DM3_ST_G']);
$DM3_MT_G= htmlspecialchars($_POST['DM3_MT_G']);
$DM3_LT_G= htmlspecialchars($_POST['DM3_LT_G']);
$DM3_ST_T= htmlspecialchars($_POST['DM3_ST_T']);
$DM3_MT_T= htmlspecialchars($_POST['DM3_MT_T']);
$DM3_LT_T= htmlspecialchars($_POST['DM3_LT_T']);
$DM4_ST_G= htmlspecialchars($_POST['DM4_ST_G']);
$DM4_MT_G= htmlspecialchars($_POST['DM4_MT_G']);
$DM4_LT_G= htmlspecialchars($_POST['DM4_LT_G']);
$DM4_ST_T= htmlspecialchars($_POST['DM4_ST_T']);
$DM4_MT_T= htmlspecialchars($_POST['DM4_MT_T']);
$DM4_LT_T= htmlspecialchars($_POST['DM4_LT_T']);
$DM5_ST_G= htmlspecialchars($_POST['DM5_ST_G']);
$DM5_MT_G= htmlspecialchars($_POST['DM5_MT_G']);
$DM5_LT_G= htmlspecialchars($_POST['DM5_LT_G']);
$DM5_ST_T= htmlspecialchars($_POST['DM5_ST_T']);
$DM5_MT_T= htmlspecialchars($_POST['DM5_MT_T']);
$DM5_LT_T= htmlspecialchars($_POST['DM5_LT_T']);
$DM6_ST_G= htmlspecialchars($_POST['DM6_ST_G']);
$DM6_MT_G= htmlspecialchars($_POST['DM6_MT_G']);
$DM6_LT_G= htmlspecialchars($_POST['DM6_LT_G']);
$DM6_ST_T= htmlspecialchars($_POST['DM6_ST_T']);
$DM6_MT_T= htmlspecialchars($_POST['DM6_MT_T']);
$DM6_LT_T= htmlspecialchars($_POST['DM6_LT_T']);
$DM7_ST_G= htmlspecialchars($_POST['DM7_ST_G']);
$DM7_MT_G= htmlspecialchars($_POST['DM7_MT_G']);
$DM7_LT_G= htmlspecialchars($_POST['DM7_LT_G']);
$DM7_ST_T= htmlspecialchars($_POST['DM7_ST_T']);
$DM7_MT_T= htmlspecialchars($_POST['DM7_MT_T']);
$DM7_LT_T= htmlspecialchars($_POST['DM7_LT_T']);
$DM8_ST_G= htmlspecialchars($_POST['DM8_ST_G']);
$DM8_MT_G= htmlspecialchars($_POST['DM8_MT_G']);
$DM8_LT_G= htmlspecialchars($_POST['DM8_LT_G']);
$DM8_ST_T= htmlspecialchars($_POST['DM8_ST_T']);
$DM8_MT_T= htmlspecialchars($_POST['DM8_MT_T']);
$DM8_LT_T= htmlspecialchars($_POST['DM8_LT_T']);
$saveRequest->bindParam(':DM1_ST_G',$DM1_ST_G);
$saveRequest->bindParam(':DM1_MT_G',$DM1_MT_G);
$saveRequest->bindParam(':DM1_LT_G',$DM1_LT_G);
$saveRequest->bindParam(':DM1_ST_T',$DM1_ST_T);
$saveRequest->bindParam(':DM1_MT_T',$DM1_MT_T);
$saveRequest->bindParam(':DM1_LT_T',$DM1_LT_T);
$saveRequest->bindParam(':DM2_ST_G',$DM2_ST_G);
$saveRequest->bindParam(':DM2_MT_G',$DM2_MT_G);
$saveRequest->bindParam(':DM2_LT_G',$DM2_LT_G);
$saveRequest->bindParam(':DM2_ST_T',$DM2_ST_T);
$saveRequest->bindParam(':DM2_MT_T',$DM2_MT_T);
$saveRequest->bindParam(':DM2_LT_T',$DM2_LT_T);
$saveRequest->bindParam(':DM3_ST_G',$DM3_ST_G);
$saveRequest->bindParam(':DM3_MT_G',$DM3_MT_G);
$saveRequest->bindParam(':DM3_LT_G',$DM3_LT_G);
$saveRequest->bindParam(':DM3_ST_T',$DM3_ST_T);
$saveRequest->bindParam(':DM3_MT_T',$DM3_MT_T);
$saveRequest->bindParam(':DM3_LT_T',$DM3_LT_T);
$saveRequest->bindParam(':DM4_ST_G',$DM4_ST_G);
$saveRequest->bindParam(':DM4_MT_G',$DM4_MT_G);
$saveRequest->bindParam(':DM4_LT_G',$DM4_LT_G);
$saveRequest->bindParam(':DM4_ST_T',$DM4_ST_T);
$saveRequest->bindParam(':DM4_MT_T',$DM4_MT_T);
$saveRequest->bindParam(':DM4_LT_T',$DM4_LT_T);
$saveRequest->bindParam(':DM5_ST_G',$DM5_ST_G);
$saveRequest->bindParam(':DM5_MT_G',$DM5_MT_G);
$saveRequest->bindParam(':DM5_LT_G',$DM5_LT_G);
$saveRequest->bindParam(':DM5_ST_T',$DM5_ST_T);
$saveRequest->bindParam(':DM5_MT_T',$DM5_MT_T);
$saveRequest->bindParam(':DM5_LT_T',$DM5_LT_T);
$saveRequest->bindParam(':DM6_ST_G',$DM6_ST_G);
$saveRequest->bindParam(':DM6_MT_G',$DM6_MT_G);
$saveRequest->bindParam(':DM6_LT_G',$DM6_LT_G);
$saveRequest->bindParam(':DM6_ST_T',$DM6_ST_T);
$saveRequest->bindParam(':DM6_MT_T',$DM6_MT_T);
$saveRequest->bindParam(':DM6_LT_T',$DM6_LT_T);
$saveRequest->bindParam(':DM7_ST_G',$DM7_ST_G);
$saveRequest->bindParam(':DM7_MT_G',$DM7_MT_G);
$saveRequest->bindParam(':DM7_LT_G',$DM7_LT_G);
$saveRequest->bindParam(':DM7_ST_T',$DM7_ST_T);
$saveRequest->bindParam(':DM7_MT_T',$DM7_MT_T);
$saveRequest->bindParam(':DM7_LT_T',$DM7_LT_T);
$saveRequest->bindParam(':DM8_ST_G',$DM8_ST_G);
$saveRequest->bindParam(':DM8_MT_G',$DM8_MT_G);
$saveRequest->bindParam(':DM8_LT_G',$DM8_LT_G);
$saveRequest->bindParam(':DM8_ST_T',$DM8_ST_T);
$saveRequest->bindParam(':DM8_MT_T',$DM8_MT_T);
$saveRequest->bindParam(':DM8_LT_T',$DM8_LT_T);
$saveRequest->bindParam(':user_id',$user_id);
$saveRequest->execute();
$saveRequest->closeCursor();
}
还有 html:
<form id="theForm" enctype="multipart/form-data" action="index.php?action=saveBoardInfo" method="post">
<table>
<thead>
<th class="head_row"> TITLES</th>
<th class="head_row" >SINGULAR SAMPLE PROCESS</th>
<th class="head_row" >FILE</th>
<th class="head_row" >MEDIUM SAMPLE PROCESS</th>
<th class="head_row" >FILE</th>
<th class="head_row" >LARGE SAMPLE PROCESS</th>
<th class="head_row" >FILE</th>
</thead>
<tbody>
<?php
foreach ($names as $number=>$domain) {
?>
<!-- FIRST HALF ROW -->
<tr <?=$number+1?>">
<!-- 2 merged rows-->
<td not_editable" rowspan="2">
<span class="color_category" style="background-color:<?=$color[$number]?>;"></span>
<span ><?=$number + 1 ?></span>
</td>
<!-- Description cell ST-->
<td class="inputContainerTdCell">
<textarea id="<?='DM'.($number+1) .'_'.'ST_G'?>" name="<?='DM'.($number+1) .'_'.'ST_G'?>" class="userInput" value="" placeholder="SINGULAR TEST SAMPLE GENERAL DESCRIPTION"><?= htmlspecialchars($board_items['DM'.($number+1) .'_'.'ST_G'])?></textarea>
</td>
<!-- Description cell MT-->
<td class="inputContainerTdCell">
<textarea id="<?='DM'.($number+1) .'_'.'LT_G'?>" name="<?='DM'.($number+1) .'_'.'MT_G'?>" class="userInput" value="" placeholder="MEDIUM TEST SAMPLE GENERAL DESCRIPTION"><?= htmlspecialchars($board_items['DM'.($number+1) .'_'.'LT_G'])?></textarea>
</td>
<!-- Description cell LT-->
<td class="inputContainerTdCell">
<textarea id="<?='DM'.($number+1) .'_'.'LT_G'?>" name="<?='DM'.($number+1) .'_'.'LT_G'?>" class="userInput" value="" placeholder="LARGE TEST SAMPLE DESCRIPTION"><?= htmlspecialchars($board_items['DM'.($number+1) .'_'.'LT_G'])?></textarea>
</td>
<!-- File import part not mentionned here: 2 merged rows-->
<!-- SECOND HALF ROW -->
<tr>
<td class="inputContainerTdCell userInput">
<textarea id="<?='DM'.($number+1) .'_'.'ST_T'?>" name="<?='DM'.($number+1) .'_'.'ST_T'?>" value="" placeholder="SINGULAR TEST IN PREPARATION"><?= htmlspecialchars($board_items['DM'.($number+1) .'_'.'ST_T'])?></textarea>
</td>
<td class="inputContainerTdCell userInput">
<textarea id="<?='DM'.($number+1) .'_'.'MT_T'?>" name="<?='DM'.($number+1) .'_'.'MT_T'?>" value="" placeholder="MEDIUM TEST IN PREPARATION"><?= htmlspecialchars($board_items['DM'.($number+1) .'_'.'MT_T'])?></textarea>
</td>
<td class="inputContainerTdCell userInput">
<textarea id="<?='DM'.($number+1) .'_'.'LT_T'?>" name="<?='DM'.($number+1) .'_'.'LT_T'?>" value="" placeholder="LARGE TEST IN PREPARATION"><?= htmlspecialchars($board_items['DM'.($number+1) .'_'.'LT_T'])?></textarea>
</td>
</tr>
<!-- SEPARATORS: INVISIBLE SEPARATION ROW -->
<tr style="height:2px;"></tr>
<?php
}
?>
</tbody>
</table>
</form>
最佳答案
您的代码表明数据库结构非常差。拥有大量这样的列说明非常not normal数据库。也就是说,您正在尽最大努力利用您拥有的数据库;不过,有几点可以显着压缩代码。
在实际以 HTML 形式显示数据之前,您不会转义 HTML 显示的数据。切勿将其存储在转义的数据库中,否则当有人想要 PDF 中的数据或输出到命令行时,您会不高兴。
PDO不需要绑定(bind)参数;仅在不明确的情况下才需要这样做,例如未正确推断数据类型,或者需要从存储过程取回数据。只需将参数数组传递给执行函数即可。
我还压缩了用于构建查询的代码,并且参数数组是在同一循环内从 $_POST
构建的。
<?php
public function saveInfos()
{
$UM = new UserManager;
if(isset($_SESSION['user_pseudo'])){
$user_id = $UM->getUserId($_SESSION['user_pseudo']);
}
$DB = $this->dbConnect();
$nbr_of_domain = $this->getNumberOfDomains();
$fields = ["ST_G", "MT_G", "LT_G", "ST_T", "MT_T", "LT_T"];
//BUILD QUERY AND PARAMETERS
$params[':user_id'] = $user_id;
for($i = 1; $i <= $nbr_of_domain; $i++) {
foreach ($fields as $field) {
$domain_assig[] = "DM{$i}_{$field} = :DM{$i}_{$field}";
$params[":DM{$i}_{$field}"] = $_POST["DM{$i}_{$field}"];
// if passing parameters to execute() truly is a problem,
// you could delete the line above and then run this same
// loop again to bind parameters, as in the comment below
}
}
$req = sprintf(
"UPDATE user_board_items SET %s WHERE user_id=:user_id",
implode(",", $domain_assig)
);
//PREPARING REQUEST
$saveRequest = $DB->prepare($req);
// if passing parameters to execute() truly is a problem...
/*
$saveRequest->bindParam(":user_id", $user_id);
for($i = 1; $i <= $nbr_of_domain; $i++) {
foreach ($fields as $field) {
$saveRequest->bindParam(":DM{$i}_{$field}", $_POST["DM{$i}_{$field}"]);
}
}
*/
$saveRequest->execute($params);
$saveRequest->closeCursor();
}
关于数据库规范化,您的数据库结构当前如下所示:
+----+---------+----------+----------+----------+ +----------+
| id | user_id | DM1_ST_G | DM1_MT_G | DM1_LT_G | ... | DM8_LT_T |
+----+---------+----------+----------+----------+ +----------+
| 17 | 12345 | aaa | aaa | aaa | ... | hhh |
+----+---------+----------+----------+----------+ +----------+
它应该看起来像这样:
+----+---------+----+------+------+------+------+------+------+
| id | user_id | DM | ST_G | MT_G | LT_G | ST_T | MT_T | LT_T |
+----+---------+----+------+------+------+------+------+------+
| 11 | 12345 | 1 | aaa | aaa | aaa | aaa | aaa | aaa |
| 12 | 12345 | 2 | bbb | bbb | bbb | bbb | bbb | bbb |
...
| 18 | 12345 | 8 | hhh | hhh | hhh | hhh | hhh | hhh |
+----+---------+----+------+------+------+------+------+------+
然后您可以根据用户 ID 选择任意行数。想象一下这样一种情况,您有几十万行,并且您决定添加另一组 DM9_*
列。现在这样,整个表都要重建,你的代码也要调整,很乱。
关于php - mySQL-PHP : how to prepare queries with variables number of variables,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58982206/