【问题标题】:Suddenly MYSQL "Malformed packet" on LOAD DATA LOCAL INFILE after two years of working工作两年后 LOAD DATA LOCAL INFILE 突然出现 MYSQL“格式错误的数据包”
【发布时间】:2019-08-26 19:32:57
【问题描述】:

这是一项工作了两年的夜间工作。 PHP 文件将一个 txt 文件导入 MYSQL 数据库。今天在导入 TXT 文件时突然收到格式错误的数据包。我注意到服务器只运行了 23 小时,所以我认为 GoDaddy 可能已经更新了一些东西。

MYSQL 版本 = 5.6.43-cll-lve

local_infile = 开启

如果没有“本地”,我会收到错误,“用户访问被拒绝”,我尝试授予 FILE,但是通过 SSH 获取 mysql CLI 访问时遇到问题(以前从未需要它)并且 PHP MY Admin 没有访问权限。

我花了一整天的时间,不知道该怎么办。我也尝试将文件设置为 777。

我已经尝试删除截断部分​​并仅进行导入,将导入文件剔除到 3 行,使用以前工作的旧导入文件 - 无法正面或反面。

require('config_dev.php');
$path = '/home/pro/public_html/upload/IDUpload_dev.txt';
$mysqli = new mysqli($hostname,$username, $password, $dbname);

if ($mysqli->connect_error) {
  die('Error : ('. $mysqli->connect_errno .') '. $mysqli->connect_error);
}

$sql1 = "TRUNCATE TABLE Accounts;";

if (!$mysqli->query($sql1)) {
    echo "\nQuery execute failed: ERRNO: (" . $mysqli->errno . ") " . $mysqli->error;
} else {
    echo ("Truncated<br>");
}

$sql2 = "LOAD DATA LOCAL INFILE '".$path."' INTO TABLE Accounts
        FIELDS TERMINATED BY ','
        LINES TERMINATED BY '\n'
        IGNORE 1 LINES
        (acct,type,zip)";

if (!$mysqli->query($sql2)) {
    echo "\nQuery execute failed: ERRNO: (" . $mysqli->errno . ") " . $mysqli->error;
} else {
    echo ("Imported.");
}

mysqli_close($mysqli);

【问题讨论】:

  • “我注意到服务器只运行了 23 小时,所以我认为 GoDaddy 可能已经更新了一些东西。” 所以先联系 GoDaddy 询问他们是否更新了一些东西。跨度>
  • 他们的低级支持根本不会知道任何事情。这不会有帮助。
  • “他们的低级别支持根本不会知道任何事情。那没有帮助”我们无法访问那里的服务器,也不知道什么他们现在更新了吗?所以在这里发帖也无济于事......也许花更多的钱通过更好的虚拟主机获得服务,那里的支持更好?
  • :( 我的代码错误的可能性比 GoDaddy 的服务器更可能受到责备,即使他们确实更新了。真的只是需要一些帮助,但感谢您的 cmets。
  • @RaymondNijland 请参阅下面的有用评论/解决方案,以防您将来需要帮助其他人。

标签: php mysql file mysqli import


【解决方案1】:

要使用LOAD DATA INFILE LOCAL,需要在连接前启用MYSQLI_OPT_LOCAL_INFILE

您应该SHOW GLOBAL VARIABLES LIKE 'local_infile' 看看是否在服务器上启用了这也是必需的。

【讨论】:

  • 谢谢,我试过了,可以看到“local_infile ON”。
  • 但我不明白你的第一行,我只是做了 SHOW Vars... 我专门搜索了它并添加了这个: mysqli_options($mysqli, MYSQLI_OPT_LOCAL_INFILE, true);初始化工作后!我爱你!从工作两年到昨晚,会发生什么变化?
  • 默认连接选项发生了某种变化,不知道。也许 GoDaddy 手动编译默认值不同。不会让我感到惊讶。确保您撤消文件权限并授予hackery。
  • Nice catch @danblack 我认为phpinfo() 也不会暴露mysqli_options() 所以你可以看到问题所在.. PHP 也没有原生函数来查看mysqli_options() 的内容PHP 连接。
  • 实际上,在我的情况下,格式错误的数据包是因为用户没有访问文件的权限(本地没有解决问题)。 stackoverflow.com/a/66504584/10533962
【解决方案2】:

确保授予当前用户访问文件的权限:

先登录mysql

mysql -u root -p

然后

GRANT FILE ON *.* TO 'username'@'localhost';

【讨论】:

  • 好收获。认为需要对提供的错误消息进行修改。
【解决方案3】:

我遇到了同样的问题,一个运行良好 3 年的脚本突然开始因“格式错误的数据包”而失败。我正在使用 private database 的 OVH 托管服务器上运行。

遗憾的是,没有一个解决方案有效(GRANTMYSQLI_OPT_LOCAL_INFILE)。

摆弄之后,我注意到脚本在同一台服务器上的测试数据库上运行!

我比较了两个数据库的配置,我能发现的唯一区别是数据库排序规则

  • 在测试数据库上,我有SELECT @@collation_database == latin1_swedish_ci
  • 在不再工作的生产数据库上,我有SELECT @@collation_database == utf8_unicode_ci

我更改了生产数据库的排序规则...

ALTER DATABASE DB_PROD_NAME CHARACTER SET latin1 COLLATE latin1_swedish_ci;

它成功了!(即使所有表都使用utf8_unicode_ci

好吧,它可以工作,但所有字符都被破坏了。

但这迫使我研究编码问题,从而找到正确的解决方案。

使用LOAD DATA LOCAL INFILE ... CHARACTER SET 'utf8mb4' ... 我能够得到真正的错误:

ERROR : Incorrect string value: '\xF0\x9F\x93\x8B' for column ...

\xF0\x9F\x93\x8B value is actually a perfectly fine UTF8-encoded character:剪贴板表情符号?

但是,它是在 4 个字节上定义的(就像大多数表情符号一样)。

如前所述,我的表和列使用排序规则utf8_unicode_ci。所以应该不错吧?除了……不是! mySQL 的utf8 实现存在严重缺陷,因为它只允许表示最多 3 个字节的 UTF8! Seetheselinks了解更多背景信息。

mySQL 中 UTF8 的全新且正确的现代实现称为 utf8mb4

所以最终的解决方案是简单地将所有表和列迁移到utf8mb4_unicode_ci 排序规则,瞧!问题解决了。

最后,最大的问题是理解这个极具误导性的“格式错误的数据包”错误消息到底是什么意思。

【讨论】:

    【解决方案4】:

    就我而言,解决方案非常简单。

    我完全同意@danblack 的回答。

    我将此行添加到我的 PHP 脚本中:

    @mysqli_options($con, MYSQLI_OPT_LOCAL_INFILE, true);
    

    就在插入脚本之前。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-05
      • 2018-09-12
      • 1970-01-01
      • 1970-01-01
      • 2012-06-01
      • 1970-01-01
      • 2013-10-09
      相关资源
      最近更新 更多