PHP:准备数据数组以安全插入 MySQL
PHP: preparing data array for secure insertion into MySQL
我正在从事一个需要 (安全) 将数据数组插入 MySQL 数据库的项目。我的代码当前使用 foreach
构造遍历 XML 文档,解析我选择从中提取的所有数据。
这是代码...
foreach ($xml->town as $towns) {
# -> player information
$player_id = mysqli_real_escape_string($dbconnect,$towns->player->playername['id']);
$player_name = mysqli_real_escape_string($dbconnect,$towns->player->playername);
# -> town data information
$town_name = mysqli_real_escape_string($dbconnect,$towns->towndata->townname);
$town_id = mysqli_real_escape_string($dbconnect,$towns->towndata->townname['id']);
$founded_on = mysqli_real_escape_string($dbconnect,$towns->towndata->foundeddatetime);
$population = mysqli_real_escape_string($dbconnect,$towns->towndata->population);
$capital = mysqli_real_escape_string($dbconnect,$towns->towndata->iscapitalcity);
# -> alliance info
$alliance_cap = mysqli_real_escape_string($dbconnect,$towns->towndata->isalliancecapitalcity);
# -> location information
$map_x = mysqli_real_escape_string($dbconnect,$towns->location->mapx);
$map_y = mysqli_real_escape_string($dbconnect,$towns->location->mapy);
# -> terrain information
$terrain_type_id = mysqli_real_escape_string($dbconnect,$towns->location->terraintype['id']);
$terrain_type = mysqli_real_escape_string($dbconnect,$towns->location->terraintype);
$terrain_overall_id = mysqli_real_escape_string($dbconnect,$towns->location->terrainoveralltype['id']);
$terrain_overall_type = mysqli_real_escape_string($dbconnect,$towns->location->terrainoveralltype);
在我最近询问有关 XML 解析的问题中,有人评论说我没有正确使用 mysqli_real_escape_string
。他提到我应该先提取数据,然后调用 mysqli_real_escape_string
准备数据库插入操作。
MySQL查询
我写了一个简单的 MySQL 有效的查询;尽管出于某种原因它只插入数组的第一行,而不是整个数据数组。
mysqli_query($dbconnect,
"INSERT INTO towndata (player_id, playername, town_name, town_id, founded_on, population, capital, alliance_cap, map_x, map_y, terrain_type_id, terrain_type, terrain_overall_id, terrain_overall_type)
VALUES ('$player_id', '$player_name', '$town_name', '$town_id', '$founded_on', '$population', '$capital', '$alliance_cap', '$map_x', '$map_y', '$terrain_type_id', '$terrain_type', '$terrain_overall_id', '$terrain_overall_type')"
); # end mysql statement
} # end of _foreach_ loop
现在 question/problem 部分...
为什么只插入了第一行而不是整个数据数组?
如上所述,INSERT INTO
语句有效。但是我似乎无法弄清楚 为什么 我的代码只插入第一行。应用程序的其他部分使用相同的代码,但没有表现出这种行为,这让我对原因一无所知。
使用mysqli_real_escape_string
准备数据数组(和字符串)用于安全数据库插入的correct/effective方法是什么?
我意识到这可能是一个偏好问题;但我不禁想知道是否有我不熟悉的模式或范例。
提前感谢您抽出时间提供帮助和建议。
您的 INSERT 似乎只适用于循环的第一个周期。我建议您为每个循环打印出插入字符串而不执行它,然后从您的 MySQL 客户端或 phpMyAdmin 测试您的插入语句。根据第一行之后的数据,您可能会遇到主键违规 (you can check it this way) 或其他错误。
我建议您查看 MySQLI prepared statements,而不是使用 mysqli_real_escape_string
,因为它们将为您提供编写 INSERT 语句的正确方法,避免 SQL注入问题。
$mysqli = new mysqli("localhost", "my_user", "my_password", "xxxx");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
foreach ($xml->town as $towns) {
# -> player information
$player_id = $towns->player->playername['id'];
$player_name = $towns->player->playername;
# -> town data information
$town_name = $towns->towndata->townname;
$town_id = $towns->towndata->townname['id'];
$founded_on = $towns->towndata->foundeddatetime;
$population = $towns->towndata->population;
$capital = $towns->towndata->iscapitalcity;
# -> alliance info
$alliance_cap = $towns->towndata->isalliancecapitalcity;
# -> location information
$map_x = $towns->location->mapx;
$map_y = $towns->location->mapy;
# -> terrain information
$terrain_type_id = $towns->location->terraintype['id'];
$terrain_type = $towns->location->terraintype;
$terrain_overall_id = $towns->location->terrainoveralltype['id'];
$terrain_overall_type = $towns->location->terrainoveralltype;
/* create a prepared statement */
if ($stmt = $mysqli->prepare("INSERT INTO `towndata` (`player_id`, `playername`, `town_name`, `town_id`, `founded_on`, `population`, `capital`, `alliance_cap`, `map_x`, `map_y`, `terrain_type_id`, `terrain_type`, `terrain_overall_id`, `terrain_overall_type`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)")) {
/* bind parameters for markers */
$stmt->bind_param('ssssssssssssss', $player_id, $playername, $town_name, $town_id,$founded_on, $population, $capital, $alliance_cap,$map_x, $map_y, $terrain_type_id, $terrain_type,$terrain_overall_id, $terrain_overall_type);
/* execute query */
$stmt->execute();
}
}
其中
- i对应的变量类型为整数
- d 对应变量的类型为 double
- s 对应的变量类型为字符串
- b对应的变量是一个blob,将以数据包的形式发送
所以在上面的代码中,如果不是所有变量都是字符串,您可以更改参数绑定中的 'sssssssssssssss' 部分。
我正在从事一个需要 (安全) 将数据数组插入 MySQL 数据库的项目。我的代码当前使用 foreach
构造遍历 XML 文档,解析我选择从中提取的所有数据。
这是代码...
foreach ($xml->town as $towns) {
# -> player information
$player_id = mysqli_real_escape_string($dbconnect,$towns->player->playername['id']);
$player_name = mysqli_real_escape_string($dbconnect,$towns->player->playername);
# -> town data information
$town_name = mysqli_real_escape_string($dbconnect,$towns->towndata->townname);
$town_id = mysqli_real_escape_string($dbconnect,$towns->towndata->townname['id']);
$founded_on = mysqli_real_escape_string($dbconnect,$towns->towndata->foundeddatetime);
$population = mysqli_real_escape_string($dbconnect,$towns->towndata->population);
$capital = mysqli_real_escape_string($dbconnect,$towns->towndata->iscapitalcity);
# -> alliance info
$alliance_cap = mysqli_real_escape_string($dbconnect,$towns->towndata->isalliancecapitalcity);
# -> location information
$map_x = mysqli_real_escape_string($dbconnect,$towns->location->mapx);
$map_y = mysqli_real_escape_string($dbconnect,$towns->location->mapy);
# -> terrain information
$terrain_type_id = mysqli_real_escape_string($dbconnect,$towns->location->terraintype['id']);
$terrain_type = mysqli_real_escape_string($dbconnect,$towns->location->terraintype);
$terrain_overall_id = mysqli_real_escape_string($dbconnect,$towns->location->terrainoveralltype['id']);
$terrain_overall_type = mysqli_real_escape_string($dbconnect,$towns->location->terrainoveralltype);
在我最近询问有关 XML 解析的问题中,有人评论说我没有正确使用 mysqli_real_escape_string
。他提到我应该先提取数据,然后调用 mysqli_real_escape_string
准备数据库插入操作。
MySQL查询
我写了一个简单的 MySQL 有效的查询;尽管出于某种原因它只插入数组的第一行,而不是整个数据数组。
mysqli_query($dbconnect,
"INSERT INTO towndata (player_id, playername, town_name, town_id, founded_on, population, capital, alliance_cap, map_x, map_y, terrain_type_id, terrain_type, terrain_overall_id, terrain_overall_type)
VALUES ('$player_id', '$player_name', '$town_name', '$town_id', '$founded_on', '$population', '$capital', '$alliance_cap', '$map_x', '$map_y', '$terrain_type_id', '$terrain_type', '$terrain_overall_id', '$terrain_overall_type')"
); # end mysql statement
} # end of _foreach_ loop
现在 question/problem 部分...
为什么只插入了第一行而不是整个数据数组?
如上所述,
INSERT INTO
语句有效。但是我似乎无法弄清楚 为什么 我的代码只插入第一行。应用程序的其他部分使用相同的代码,但没有表现出这种行为,这让我对原因一无所知。使用
mysqli_real_escape_string
准备数据数组(和字符串)用于安全数据库插入的correct/effective方法是什么?我意识到这可能是一个偏好问题;但我不禁想知道是否有我不熟悉的模式或范例。
提前感谢您抽出时间提供帮助和建议。
您的 INSERT 似乎只适用于循环的第一个周期。我建议您为每个循环打印出插入字符串而不执行它,然后从您的 MySQL 客户端或 phpMyAdmin 测试您的插入语句。根据第一行之后的数据,您可能会遇到主键违规 (you can check it this way) 或其他错误。
我建议您查看 MySQLI prepared statements,而不是使用 mysqli_real_escape_string
,因为它们将为您提供编写 INSERT 语句的正确方法,避免 SQL注入问题。
$mysqli = new mysqli("localhost", "my_user", "my_password", "xxxx");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
foreach ($xml->town as $towns) {
# -> player information
$player_id = $towns->player->playername['id'];
$player_name = $towns->player->playername;
# -> town data information
$town_name = $towns->towndata->townname;
$town_id = $towns->towndata->townname['id'];
$founded_on = $towns->towndata->foundeddatetime;
$population = $towns->towndata->population;
$capital = $towns->towndata->iscapitalcity;
# -> alliance info
$alliance_cap = $towns->towndata->isalliancecapitalcity;
# -> location information
$map_x = $towns->location->mapx;
$map_y = $towns->location->mapy;
# -> terrain information
$terrain_type_id = $towns->location->terraintype['id'];
$terrain_type = $towns->location->terraintype;
$terrain_overall_id = $towns->location->terrainoveralltype['id'];
$terrain_overall_type = $towns->location->terrainoveralltype;
/* create a prepared statement */
if ($stmt = $mysqli->prepare("INSERT INTO `towndata` (`player_id`, `playername`, `town_name`, `town_id`, `founded_on`, `population`, `capital`, `alliance_cap`, `map_x`, `map_y`, `terrain_type_id`, `terrain_type`, `terrain_overall_id`, `terrain_overall_type`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)")) {
/* bind parameters for markers */
$stmt->bind_param('ssssssssssssss', $player_id, $playername, $town_name, $town_id,$founded_on, $population, $capital, $alliance_cap,$map_x, $map_y, $terrain_type_id, $terrain_type,$terrain_overall_id, $terrain_overall_type);
/* execute query */
$stmt->execute();
}
}
其中
- i对应的变量类型为整数
- d 对应变量的类型为 double
- s 对应的变量类型为字符串
- b对应的变量是一个blob,将以数据包的形式发送
所以在上面的代码中,如果不是所有变量都是字符串,您可以更改参数绑定中的 'sssssssssssssss' 部分。