【问题标题】:Importing CSV data using PHP/MySQL - Mysqli syntax使用 PHP/MySQL 导入 CSV 数据 - Mysqli 语法
【发布时间】:2013-12-24 12:29:21
【问题描述】:

在这个问题的底部,最终工作的最终代码!

正在尝试实现这一点 (Importing CSV data using PHP/MySQL)。我一定快到了……

notes1:我的 $sql 直接来自复制/粘贴 phpmyadmin(生成 php 代码)并在 phpmyadmin 中运行良好。

note2:如果我注释 $sql="DELETE FROM dbase" 行,代码运行正常(并且表已清理)。

所以如果我知道我的 sql 是正确的并且我的代码可以运行其他 sql,为什么下面的不运行?!我得到:

在非对象上调用成员函数 execute() - 用于行

$stmt->execute();

完整代码:

<?php
$mysqli  =  new mysqli('localhost','root','pass','dbase');
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}

$sql = "LOAD DATA INFILE \'./myfile.csv\' INTO TABLE tab\n"
. " FIELDS TERMINATED BY \',\'\n"
. " LINES TERMINATED BY \'\\r\\n\'\n"
. " IGNORE 1 LINES";

//$sql="DELETE FROM dbase";

$stmt=$mysqli->prepare($sql);
$stmt->execute(); 
$stmt->close();
$mysqli->close();
?>

提前通知!

编辑:

进行了以下更改,但仍然无法正常工作!

新代码:

<?php

$mysqli  =  new mysqli('localhost','root','pass','dbase');
/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

/* return name of current default database */
if ($result = $mysqli->query("SELECT DATABASE()")) {
    $row = $result->fetch_row();
    printf("Default database is %s.\n", $row[0]);
    $result->close();
}

$sql = "LOAD DATA INFILE 'C:/xampp/htdocs/myfile.csv' INTO TABLE tab
        FIELDS TERMINATED BY ','
    LINES TERMINATED BY '\\r\\n'
    IGNORE 1 LINES";

echo "<br>";
echo "<br>";
echo $sql;
echo "<br>";
echo "<br>";
$stmt=$mysqli->prepare($sql);

/* Prepared statement, stage 1: prepare */
if (!($stmt = $mysqli->prepare($sql))) 
{    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}


// NOTE HERE WE'RE DUMPING OUR OBJ TO SEE THAT IT WAS 
// CREATED AND STATUS OF PREPARE AND THEN KILLING SCRIPT   
var_dump($mysqli);
exit();

//$sql="DELETE FROM intrasdump

$stmt=$mysqli->prepare($sql);
$stmt->execute(); 
$stmt->close();
$mysqli->close();
?>

我在浏览器中看到的内容如下:

默认数据库是 dbname。

将数据输入文件 'C:/xampp/htdocs/myfile.csv' 加载到表选项卡字段中以 ',' 终止的行 '\r\n' 忽略 1 行

Prepare failed: (1295) 在准备好的语句协议中不支持此命令 Yetobject(mysqli)#1 (19) { ["affected_rows"]=> int(-1) ["client_info"]=> string( 79) "mysqlnd 5.0.11-dev - 20120503 - $Id: 40933630edef551dfaca71298a83fad8d03d62d4 $" ["client_version"]=> int(50011) ["connect_errno"]=> int(0) ["connect_error"]=> NULL [" errno"]=> int(1295) ["error"]=> string(68) "prepared statement 协议尚不支持此命令" ["error_list"]=> array(0) { } ["field_count" ]=> int(1) ["host_info"]=> string(20) "localhost via TCP/IP" ["info"]=> NULL ["insert_id"]=> int(0) ["server_info"]= > string(6) "5.6.11" ["server_version"]=> int(50611) ["stat"]=> string(133) "Uptime: 7993 Threads: 2 Questions: 865 Slow queries: 0 Opens: 75 Flush表:1 打开表:每秒 68 次查询平均:0.108" ["sqlstate"]=> string(5) "00000" ["protocol_version"]=> int(10) ["thread_id"]=> int(117) ["warning_count"]=> int(0) }

注意:如果我将上面回显的 sql 字符串复制粘贴到 mysql 提示符中,它运行得很好。那应该意味着文件位置问题和sql字符串本身都很好,不是吗???

怎么这么难?!

编辑 3.

所有答案和 cmets 的 Tks。下面的最终代码版本有效:

<?php

$mysqli  =  new mysqli('localhost','root','pass','dbname');
/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$sql = "LOAD DATA INFILE 'C:/xampp/htdocs/myfile.csv' INTO TABLE tab
        FIELDS TERMINATED BY ','
        LINES TERMINATED BY '\\r\\n'
        IGNORE 1 LINES";

//Try to execute query (not stmt) and catch mysqli error from engine and php error
if (!($stmt = $mysqli->query($sql))) {
    echo "\nQuery execute failed: ERRNO: (" . $mysqli->errno . ") " . $mysqli->error;
};
?>

有用的注释:

  • 注意文件路径使用 frw-slash 而不是 windows-default 反斜杠。 Orderwise 只会记下工作。天知道我是怎么想出来的……

  • 利用答案中提供的许多调试代码。我想一种有效的方法来检查你的 sql 是否正确回显 (echo $sql) 它并在你的 sql 提示符中复制/粘贴。不要相信 phpmyadmin 'create php PHP code' 功能。

  • 请记住“准备好的 stmts 不支持加载数据”

【问题讨论】:

  • 我认为 phpmyadmin 假设您会将查询括在单引号中,以便将其转义。只需在所有 ' 之前删除 \ ,我认为它应该可以工作。或者将查询括在 ' 而不是双引号 "
  • 当您在外部使用双引号时,您不需要转义单引号。不是问题,但是根本不需要 \n 和 \r ,并且会使您的字符串混乱。您可以安全地删除它们。
  • @fvu 说的,我没看 :)
  • @fvu - 实际上最好指定 LINES。默认情况下没有 LINES.. 语句,mysql 在 v5.6 中查找 LINES TERMINATED BY '\n' 而不是 '\r\n'。
  • @cerd 我的意思是语句字符串部分末尾的 \n,而不是行终止符定义,但我现在发现这根本不清楚......

标签: php sql csv mysqli load-data-infile


【解决方案1】:

您可能应该设置警卫来检测准备调用何时失败:

/* Prepared statement, stage 1: prepare */
if (!($stmt = $mysqli->prepare("INSERT INTO test(id) VALUES (?)"))) {
    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}

来源:http://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php

我还要检查LOAD DATA INFILE 命令的路径。 Phpmyadmin 可能正在设置不同的路径变量。如果您尝试临时放置绝对 unix 路径(并确保 mysql 对该目录具有适当的权限),它可能会清除问题。

但是,无论哪种情况,您都应该从 mysql 客户端输出错误,以便更好地了解导致问题的原因。

最后,我会尝试直接在 MySQL 命令行客户端中执行命令。如果在 phpmysql 或 mysqli php 客户端中发生任何“魔术”,它将通过使用 mysql cli 客户端显示,因为其中两个客户端将成功,而一个将失败(与您的假设相比)。

我之前遇到过类似的问题,它最终成为 MySQL 转义分隔符的奇怪方式,所以我想看看你是否正确地转义了 TERMINATED BY 参数。

【讨论】:

  • 我一步一步地跟着你,我仍然没有 Homer6。请看看我的编辑。
  • 我建议的第一步是输出错误信息。事实证明,这正是问题所在:“准备好的语句协议 yetobject(mysqli)#1 不支持此命令”很高兴您找到了问题。
  • @Homer6 很好地调用了上面的代码,我将它添加到上面的答案中,作为说明问题以及解决方法的一种手段。
【解决方案2】:

Homer6 陈述的内容,并且可能:

$sql = "LOAD DATA INFILE './myfile.csv' INTO TABLE tab"
. " FIELDS TERMINATED BY ','"
. " LINES TERMINATED BY '\\r\\n'"
. " IGNORE 1 LINES";

可能还需要检查文件的路径。我不知道 ./ 在查询中与什么相关。可能不是 PHP 文件的位置。

【讨论】:

  • 我在使用 LOAD DATA 的准备时遇到了更大的问题,但确实你上面的 sql 字符串是有效的!
【解决方案3】:

编辑可能的解决方案:准备好的 stmts 不支持 LOAD DATA

如果你使用mysqli_query - 而不是mysqli-&gt;prepare ..->execute();这应该有效。

所以:

//Connect as normal above
$sql = "LOAD DATA INFILE '/myfile.csv' INTO TABLE tab"
. " FIELDS TERMINATED BY ','"
. " LINES TERMINATED BY '\r\n'"
. " IGNORE 1 LINES";

//$sql="DELETE FROM dbase";
// $stmt = $mysqli->query($sql);
// Integrate other posters good recc to catch errors:

//Try to execute query (not stmt) and catch mysqli error from engine and php error
if (!($stmt = $mysqli->query($sql))) {
    echo "\nQuery execute failed: ERRNO: (" . $mysqli->errno . ") " . $mysqli->error;
}

仍然对 var_dump($mysqli) 有用,以查看结果我被拒绝访问,因为在我的环境中我们不允许加载文件,但这告诉我引擎成功解析并尝试执行查询。

您需要获得更好的错误信息,可能会发生一些情况,这就是我要深入研究的方法:

达到这一点的诊断过程:

$sql = "LOAD DATA INFILE ...";
echo $sql;
$stmt=$mysqli->prepare($sql);

// NOTE HERE WE'RE DUMPING OUR OBJ TO SEE THAT IT WAS 
// CREATED AND STATUS OF PREPARE AND THEN KILLING SCRIPT   
var_dump($mysqli);
exit();

我的盒子上的结果(不是最好的表示):

  object(mysqli)#1 (18) {
  ...
  string(68) "This command is not supported in the 
              prepared statement protocol yet"

2。您可能会看到的其他错误

文件权限不足或文件位置不正确

phpMyAdmin 是相当沙盒的,其工作方式与 mysqli/php 完全不同。

从 MySQL Docs 解决以下问题,并阅读本节。就像我说的,LOAD..FILE 是一个非常敏感的操作,有很多限制。 LOAD...FILEMySQL Docs

出于安全原因,在读取服务器上的文本文件时, 文件必须位于数据库目录中或可读 所有。此外,要在服务器文件上使用 LOAD DATA INFILE,您必须具有 文件权限。请参阅第 6.2.1 节,“MySQL 提供的权限”。 对于非本地加载操作,如果 secure_file_priv 系统变量 设置为非空目录名,要加载的文件必须是 位于该目录中。

【讨论】:

  • 我按照你的答案的每一步。我确实收到了我在您的框中读到的相同错误=“准备好的语句协议尚不支持此命令”。请看看我的编辑!
  • @Amariani 我调查了这个。有关可能的解决方案,请参阅上面我编辑的答案。
  • 宾果游戏!像魅力一样工作!我想知道您是如何发现“准备好的 stmts 不支持加载数据”的。我是否应该将我的最终解决方案作为对 LOAD DATA 其他受害者的问题的编辑发布?我对这个 stackflow 有点陌生。无论如何,tks 数不胜数!
  • @AMariani - 很高兴这有效。老实说,除了 MySQL 文档中的 cmets 之外,我找不到此错误的具体参考。您也不能 DROP 表。也许请接受可能遇到此问题的其他人的答案。随着 mysql_ 在 php 5.5 中被弃用,许多其他人在转到 mysqli_、PDO 等时会遇到这个问题。
【解决方案4】:

你必须使用 MySQL 的 root 用户 如果仍然无法运行,请使用此代码检查错误输出

var_dump(mysqli_error($conn));

【讨论】:

    猜你喜欢
    • 2012-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多