3 回答
TA贡献1811条经验 获得超4个赞
您不应该将表单字段作为列表重复name0
,name1
..name99
相反,您需要将它们作为数组发送,例如:data[0][name]
..data[99][name]
另外,最好使用 PHP 生成 HTML,以免违反DRY 规则,您会意识到将来何时需要使用重复字段编辑表单:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/style.css">
<meta charset="utf-8">
</head>
<body>
<form action="php/insert-multi-ing.php" method="POST">
<table>
<tr>
<th>Nom Ingrédient</th>
<th>Prix</th>
<th>Prix Ingrédient</th>
<th>Quantite Ingrédient</th>
<th>Unite</th>
</tr>
<?php
for ($i = 0; $i < 10; $i++) {
echo "
<tr>
<td><input type='text' name='data[{$i}][name]'></td>
<td><input type='text' name='data[{$i}][prix]'></td>
<td><input type='text' name='data[{$i}][prixn]'></td>
<td><input type='text' name='data[{$i}][quantite]'></td>
<td>
<select name='data[{$i}][unite]' id='unite_{$i}'>
<option>kg</option>
<option>G</option>
<option>L</option>
<option>Ml</option>
<option>Cl</option>
<option>Piece</option>
</select>
</td>
</tr>
";
}
?>
</table>
<button>Ajouter ingrédient</button>
</form>
</body>
</html>
以下是在 PHP 中将其作为多维数组进行访问并使用准备好的语句插入到数据库的示例。请记住,我在这里使用 PDO 而不是 mysqli,我建议您:
<?php
$data = $_POST['data'] ?? null;
if (!is_null($data)) {
$pdo = new PDO("mysql:host=127.0.0.1;dbname=test;charset=utf8", "yourusername", "yourpassword");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("
INSERT
INTO ingredient (name, prix, prixn, unite, quantite, date)
VALUES (:name, :prix, :prixn, :unite, :quantite, NOW())
");
$stmt->bindParam('name', $name);
$stmt->bindParam('prix', $prix);
$stmt->bindParam('prixn', $prixn);
$stmt->bindParam('quantite', $quantite);
$stmt->bindParam('unite', $unite);
foreach ($data as $item) {
// Adds some data validation to make sure you won't save million empty rows,
// also add custom validation for other fields (if any)
$name = checkValue($item['name']);
$prix = checkValue($item['prix']);
$prixn = checkValue($item['prixn']);
$quantite = floatval($item['quantite']);
$unite = checkValue($item['unite']);
if (!is_null($name) && !is_null($prix) && !is_null($prixn) && $quantite > 0) {
$stmt->execute();
}
}
}
/**
* check if the string value is not null and not empty
*
* @param $value
*
* @return string|null
*/
function checkValue($value)
{
return (is_null($value) || trim($value) == '') ? null : $value;
}
请注意,您的代码很混乱,很可能我在表单中使用了错误的列名称或字段名称,只需修复它即可。一般来说,这是有效的。
TA贡献1821条经验 获得超6个赞
您的代码会受到 SQL 注入。最好使用参数化查询。它们负责引用、修复可能包括 SQL 注入的数据等。重复执行相同的语句时它们的执行速度也更快。
注意:代码未经测试,可能需要一些语法检查和其他更正
<?php
// Create PDO connection
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
// Create list of base column names
$colList = array(
'name',
'prix',
'prixn',
'uniteing'
);
// Create array to hold column values from $_POST
$val = Array(null,null,null,null);
// Prepare SQL statement with place holders, be sure to explicitly list the table column names. Substitute the actual column names for those below.
$stmt = $dbh->prepare("INSERT INTO ingredient (`namex`,`prixx`,`prixnx`,`uniteingx`) VALUES (:namex,:prixx,:prixnx,:uniteingx)");
// Bind each array value to a place holder
$stmt->bindParam(':namex',$val[1]);
$stmt->bindParam(':prixx',$val[2]);
$stmt->bindParam(':prinx',$val[3]);
$stmt->bindParam(':uniteingx',$val[4]);
// Step through the column name suffix values from the form
for($i=0;$i<=10;$i++) {
// Special case for the first (0) value (i.e. no suffix)
$suffix = $i > 0 ? $i : '';
// Load the 5 column values from the post variables into the $val array
foreach($colList as $colNum, $colName) {
$val[$colNum] = $_POST[$colName . $suffix];
}
// Execute the SQL statement above with the current values in $val
$stmt->execute();
}
?>
TA贡献1827条经验 获得超8个赞
首先,制作您的 html 表单,使其适合目的并且不违反 html 文档标准。
您应该在循环内生成输入字段的行。
您应该
name
使用数组语法声明每个字段的属性,以便在分组的子数组中提交行数据——这将使后续过程变得更加容易。通过简单地在字段名称后面加上[]
,您可以避免不必要的 php 语法使您的文件变得混乱。id
单个文档中不得有重复的属性。您可以在字符串末尾附加一个计数器id
,但很可能您id
根本不需要这些声明——我将省略它们。<option>
将的文本复制为其值的好处为零value
。只需省略该属性声明即可。<option>
使用测量单位白名单,这样您就不需要一遍又一遍地写出每个标签。这将提高脚本的可维护性。为了改进用户体验,请使用字段属性,例如:
title
、placeholder
、pattern
、minlength
、maxlength
、required
等,并可能type="number"
指导用户如何形成有效条目。这些简单的操作不仅有助于防止用户感到沮丧,还可以使您的应用程序免于徒劳地访问数据库和/或仅存储部分提交。
<table>
<tr>
<th>Nom Ingrédient</th>
<th>Prix Ingrédient</th>
<th>Quantite Ingrédient</th>
<th>Unite</th>
</tr>
<?php
$numberOfRows = 10;
$units = ['kg', 'G', 'L', 'ml', 'Cl', 'Piece'];
for ($i = 0; $i < $numberOfRows; ++$i) {
?>
<tr>
<td><input type="text" name="name[]"></td>
<td><input type="text" name="price[]"></td>
<td><input type="text" name="quantity[]"></td>
<td>
<select name="unit[]">
<option><?php echo implode('</option><option>', $units); ?></option>
</select>
</td>
</tr>
<?php
}
?>
</table>
至于数据库表的设置,这里有一些提示:
避免模糊的列命名,例如
date
. 将列重命名为insert_date
或created_on
或类似的名称,以便该值可以为您的脚本/项目的未来读者提供更多信息。修改表的架构
ingredients
以将 DEFAULT 值设置insert_date
为 CURRENT_DATE。这样做时,您永远不需要将此列写入 INSERT 查询 - 当您不传递该列的值时,数据库将自动使用当前日期。如果该表没有 AUTOINCRMENTing
id
列,您应该添加一列并将其设为 PRIMARY KEY。这是一项非常基本的技术,可以改善将来与表的交互,并且可以消除当您发现有人name
向表中提交了重复项时可能出现的混乱。
至于处理您提交的数据,只需遵循几个简单的步骤:
迭代
$_POST
数组并隔离要插入数据库的每一行数据。一旦隔离,您需要在执行查询之前验证并选择性地清理每一行,以便您永远不会在表中存储“坏数据”。
您正在使用
mysqli
这很好——您不需要切换到 pdo 来编写安全/稳定的代码。4 您只需生成一次准备好的语句并将变量绑定到占位符一次。只有语句的(条件)执行需要在循环内。不过,我建议您从 mysqli 的过程语法切换到面向对象的语法。它更简洁,我发现它更容易阅读。
// create a mysqli connection object e.g. $mysqli = new mysqli(...$credentials);
$sql = "INSERT INTO ingredients (`id`, `name`, `price`, `quantity`, `unit`)
VALUES (NULL, ?, ?, ?, ?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('sdds', $name, $price, $quantity, $unit); // Assumes price and quantity are float values
$failures = [];
$affectedRows = 0;
$units = ['kg', 'G', 'L', 'ml', 'Cl', 'Piece'];
foreach ($_POST['name'] as $index => $name) {
// adjust the validation/sanitization processes as you wish
$name = trim($name);
$price = trim($_POST['price'][$index]);
$quantity = trim($_POST['quantity'][$index]);
$unit = trim($_POST['unit'][$index]);
$rowNo = $index + 1;
if (!strlen($name) || !strlen($price) || !strlen($quantity) || !in_array($unit, $units)) {
$failures[] = "Missing/Invalid value on row $rowNo";
} elseif (!$stmt->execute());
$failures[] = "A syntax error has occurred"; // check your error logs
} else {
++$affectedRows;
}
}
echo "Affected Rows: $affectedRows";
if ($failures) {
echo "<ul><li>" , implode('</li><li>', $failures) , "</li></ul>";
}
一些总体建议:
避免混淆法语和英语。如果要使用法语变量名称,请使用所有法语变量。也就是说,我读过以英语为母语的人和英语作为第二语言开发人员的建议,他们指出您应该始终在代码中使用所有英语 - 这是一场辩论,我现在不会对此进行权衡。
您会注意到,我在答案中从未调用过此函数。这是因为我们永远不会将任何用户输入打印到屏幕上。证实?是的。消毒?当然。HTML 编码?没有; 不在这里,不现在。
如果这些成分行旨在与特定的
recipe
表行相关,那么您将需要建立外键关系。该recipes
表将需要一id
列,并且该ingredients
表将需要一列来recipe_id
存储相应的配方id
。假设您的 html 表单已经知道正在引用哪个菜谱,您应该<input type="hidden" name="recipe" value="<?php echo $recipeId; ?>">
在标签下的行中包含一个字段<form>
。然后,在保存数据时,您必须保存$_POST['recipe']
每个成分行的值。那么你就可以更好地使用“关系数据库”。
- 3 回答
- 0 关注
- 165 浏览
添加回答
举报