我必须构建报告网站,其中将使用来自另一个系统导出的CSV文件导入SQL数据。
我构建了代码,但我无法继续进行,在SQL中导入,我只有消息查询失败,而不是来自SQL或与数据库连接的错误。
有人可以查看我的代码并给我写信我的错误吗?我用户逃脱了数据,因为我已经出现了诸如... "John's company"
:
<?php
if(isset($_POST['import'])) {
$filename = $_FILES['file']['tmp_name'];
if($_FILES['file']['size'] > 0 ) {
$file = fopen($filename, 'r');
while (($data = fgetcsv($file, 10000, ",")) !== FALSE ) {
$data = array_map('mysqli_real_escape_string', $data);
$query = "INSERT INTO purchasing ";
$query .= "(
purchase_req,
pr_date,
pr_item,
pr_created_by,
po_created_by,
purch_group,
purchase_ord,
po_date,
po_item,
po_state,
vendor_numb,
vendor_name,
mat_desc,
gl_acc,
cost_cent,
po_qty,
po_del_date,
po_delivered_qty,
po_to_be_del
) ";
$query .= "VALUES (
'" . $data[0] . "',
'" . $data[1] . "',
'" . $data[2] . "',
'" . $data[3] . "',
'" . $data[4] . "',
'" . $data[5] . "',
'" . $data[6] . "',
'" . $data[7] . "',
'" . $data[8] . "',
'" . $data[9] . "',
'" . $data[10] . "',
'" . $data[11] . "',
'" . $data[12] . "',
'" . $data[13] . "',
'" . $data[14] . "',
'" . $data[15] . "',
'" . $data[16] . "',
'" . $data[17] . "',
'" . $data[18] . "'
) ";
$send_to_database = mysqli_query($conn, $query);
if(!$send_to_database) {
die("QUERY FAILED <br>" . mysqli_error($conn));
} else {
header("Location: index.php");
}
}
fclose($file);
}
}
?>
///建议后更新代码
<?php
if(isset($_POST['import'])) {
$filename = $_FILES['file']['tmp_name'];
if($_FILES['file']['size'] > 0 ) {
$file = fopen($filename, 'r');
$conn = new mysqli("localhost", "####", "####", "####");
if($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$stmt = $mysqli->prepare("INSERT INTO purchasing (purchase_req, pr_date, pr_item, pr_created_by, po_created_by, purch_group, purchase_ord, po_date, po_item, po_state, vendor_numb, vendor_name, mat_desc, gl_acc, cost_cent, po_qty, po_del_date, po_delivered_qty, po_to_be_del) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ");
fgetcsv($file, 10000, ",");
while(($data = fgetcsv($file, 10000, ",")) !== FALSE) {
$data = fgetcsv($file);
$stmt->bind_param("sssssssssssssssssss", $data[0], $data[1], $data[2], $data[3], $data[4], $data[5], $data[6], $data[7], $data[8], $data[9], $data[10], $data[11], $data[12], $data[13], $data[14], $data[15], $data[16], $data[17], $data[18]);
$stmt->execute();
}
fclose($file);
}
}
?>
使用第二种情况,我打印了数组,但我又无法将其发送到SQL ...
使用修订的代码,您正在使用准备和绑定参数,但是您错过了准备好的语句的好处之一:您可以准备一次并执行多次,以不同的值执行不同的值。
顺便说一句,当您绑定时,您需要一个具有与参数数量的字符字符串。在这种情况下,您需要一串长度19。
$stmt = $mysqli->prepare("INSERT INTO purchasing (purchase_req, pr_date, pr_item,
pr_created_by, po_created_by, purch_group, purchase_ord, po_date, po_item, po_state,
vendor_numb, vendor_name, mat_desc, gl_acc, cost_cent, po_qty, po_del_date,
po_delivered_qty, po_to_be_del) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ");
while(($data = fgetcsv($file, 10000, ",")) !== FALSE) {
$data = fgetcsv($file);
$stmt->bind_param("sssssssssssssssssss", $data[0], $data[1], $data[2], $data[3], $data[4], $data[5],
$data[6], $data[7], $data[8], $data[9], $data[10], $data[11], $data[12],
$data[13], $data[14], $data[15], $data[16], $data[17], $data[18]);
$stmt->execute();
}
这有点高效,因为MySQL不必为CSV输入的每一行重新使用SQL语句。
提示:我更喜欢使用PDO代替MySQLI,因为它具有使用准备好的语句的更好接口。您不必绑定任何变量。如果您将数据作为参数传递给execute()
:
$stmt = $pdo->prepare("INSERT INTO purchasing (purchase_req, pr_date, pr_item,
pr_created_by, po_created_by, purch_group, purchase_ord, po_date, po_item, po_state,
vendor_numb, vendor_name, mat_desc, gl_acc, cost_cent, po_qty, po_del_date,
po_delivered_qty, po_to_be_del) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ");
while(($data = fgetcsv($file, 10000, ",")) !== FALSE) {
$data = fgetcsv($file);
$stmt->execute($data);
}
我经常感到困惑,为什么更多的PHP开发人员不使用PDO。
pdo被认为是异国情调的,因为它在PHP 5.0天内没有包含在默认的PHP安装中。但是自PHP 5.1 PHP以来,PDO一直是官方PHP分销的一部分。奇怪的是,即使在15年后,开发人员都会避开它!
您需要养成做习惯的一件事是检查错误。在PHP和其他语言中也是如此。
mysqli函数如果有错误,则返回false。然后,您应该记录错误,以便可以将其用于故障排除。
这样:
$stmt = $mysqli->prepare(...);
if ($stmt === false) {
error_log($mysqli->error);
die("Internal error");
}
$ok = $stmt->execute();
if ($ok === false) {
error_log($stmt->error);
die("Internal error");
}
您需要在之后检查每个致电prepare()
或execute()
。这很痛苦,但是否则您将如何知道出了什么问题?
在开发和测试代码时,请在HTTP错误日志上保持窗口打开尾巴,因此您可以查看错误。
向用户输出通用错误消息是一种很好的做法,因为您不想向用户透露太多有关代码的信息。但是将更多技术信息记录到错误日志中,以便您可以自己对其进行故障排除。
为什么不简单地使用MySQL LOAD DATA INFILE
语法一次加载文件,并使用单个SQL查询?
此MySQL Buit-In是一种加载CSV文件的有效方法,同时防止SQL注入和处理引用问题。它还避免使用PHP打开和循环。根据MySQL文档:
从文本文件加载表时,请使用
LOAD DATA
。这通常比使用INSERT
语句快20倍。
这应该像:
一样简单LOAD DATA INFILE '$filename'
INTO TABLE purchasing(
purchase_req,
pr_date, pr_item,
pr_created_by,
po_created_by,
purch_group,
purchase_ord,
po_date,
po_item,
po_state,
vendor_numb,
vendor_name,
mat_desc,
gl_acc,
cost_cent,
po_qty,
po_del_date,
po_delivered_qty,
po_to_be_del
)
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY 'rn' -- or maybe 'n'?
;
nb:OPTIONALLY ENCLOSED BY '"'
选项应处理诸如"John's company"
之类的字段值。LOAD DATA INFILE
有更多有用的选项,这些选项已在上述链接文档中描述。