工作两年后,MYSQL 突然"Malformed packet"加载数据本地 INFILE



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

MYSQL Ver = 5.6.43-cll-lve

local_infile = 开

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

我花了一整天的时间,不知道该怎么办。我也尝试将文件设置为 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);

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

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

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

首先登录到mysql

mysql -u root -p

然后

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

我遇到了同样的问题,一个运行良好的脚本 3 年,突然开始因"格式错误的数据包"而失败。我正在运行具有私有数据库的 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: 'xF0x9Fx93x8B' for column ...

xF0x9Fx93x8B值实际上是一个完美的 UTF8 编码字符:剪贴板表情符号 📋

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

如前所述,我的表和列使用排序规则utf8_unicode_ci。所以应该很好吧?除了。。。不!mySQL 的utf8实现存在严重缺陷,因为它只允许表示最多 3 个字节的 UTF8!有关更多背景信息,请参阅这些链接。

在mySQL中UTF8的新的和正确的现代实现称为utf8mb4

因此,最终的解决方案只是将所有表和列迁移到utf8mb4_unicode_ci排序规则中,瞧!问题解决了。

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

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

我完全同意@danblack答案。

我在 PHP 脚本中添加了这一行:

@mysqli_options($con, MYSQLI_OPT_LOCAL_INFILE, true);

就在插入脚本之前。

最新更新