加载数据文件+ MySQL错误28000


LOAD DATA INFILE + MySQL error 28000

我想执行以下SQL查询时遇到问题:

LOAD DATA INFILE 'thelocationofmyfile.csv'
INTO TABLE test_import 
FIELDS TERMINATED BY ';'
LINES TERMINATED BY ''r'n'
IGNORE 1 LINES ( ArtID, ArtNamePharmLang, ArtNameFr, ArtNameNl, PubPrice, PercentageRebate, RebateAmount, SellingPrice, Localisation, CnkNr, EanNr, SoldQty, MinThd, MaxThd, QtyInStock, DateLastSale, VatRate, SupplierManufName, BuyPrice, InvCatCode, ArtType, ApbCatCode, ApbLegCode, PharmApbNr );

我想将 excel 文件的数据加载到数据库中的表中。当我在本地运行它时,一切正常。但是当我在服务器上执行此操作时,出现以下错误:

Uncaught exception 'PDOException' with message 'SQLSTATE[28000]: Invalid authorization specification: 1045 Access denied for user 'myuser'@'localhost' (using password: YES)'

我正在尝试在PHP(在Zend Framework中(中执行此操作。当我联系主机时,他们说我需要 FILE 权限才能执行此操作。但这是不好的做法,不建议。

我还尝试在这样的 shell 脚本中执行此操作:

#!/bin/bash
/usr/bin/mysql --host=localhost --user=theuser --password=password --database=db_database<<EOFMYSQL
LOAD DATA INFILE 'locationofmyfile.csv'
INTO TABLE test_import 
FIELDS TERMINATED BY ';'
LINES TERMINATED BY ''r'n'
IGNORE 1 LINES ( ArtID, ArtNamePharmLang, ArtNameFr, ArtNameNl, PubPrice, PercentageRebate, RebateAmount, SellingPrice, Localisation, CnkNr, EanNr, SoldQty, MinThd, MaxThd, QtyInStock, DateLastSale, VatRate, SupplierManufName, BuyPrice, InvCatCode, ArtType, ApbCatCode, ApbLegCode, PharmApbNr );
EOFMYSQL

但是我得到了同样的错误:

ERROR 1045 (28000) at line 1: Access denied for user 'user'@'localhost' (using password: YES)

更新:

我尝试像这样添加本地:

LOAD DATA LOCAL INFILE 'thelocationofmyfile.csv'

但是后来我收到此错误:

ERROR 1148 (42000) at line 1: The used command is not allowed with this MySQL version

还尝试像这样添加 --local-infile=1,但得到同样的错误

/usr/local/bin/mysql --host=127.0.0.1 --user=theuser --local-infile=1 --password=password --database=db_database

第二次更新:

我的配置文件my.cnf看起来像这样:

[mysqld]
local-infile=0
max_connections         = 50
connect_timeout         = 5
wait_timeout            = 300
max_allowed_packet      = 16M
thread_cache_size       = 128
sort_buffer_size        = 4M
bulk_insert_buffer_size = 16M
tmp_table_size          = 16M
max_heap_table_size     = 16M
key_buffer_size         = 32M
open-files-limit        = 2000
table_cache             = 400
myisam_sort_buffer_size = 8M
concurrent_insert       = 2
read_buffer_size        = 2M
read_rnd_buffer_size    = 1M
query_cache_limit       = 1M
query_cache_size        = 32M
innodb_log_file_size    = 48M
max_allowed_packet  = 32M

建立连接的位置并不重要,因为我正在使用建立连接的 shell 脚本对其进行测试。

运行时没有收到错误

/usr/bin/mysql --host=localhost --user=theuser --password=password --database=db_database<<EOFMYSQL
show tables;
EOFMYSQL

(只是我数据库中所有表的列表(

当我运行SHOW GRANTS;时,我得到:

+------------------------------------------------------------------------------------------------------------------------+
| Grants for theuser@localhost                                                                                           |
+------------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'theuser'@'localhost' IDENTIFIED BY PASSWORD '*password' |
| GRANT ALL PRIVILEGES ON `mydomain'_live`.* TO 'theuser'@'localhost'                                                    |
| GRANT ALL PRIVILEGES ON `mydomain'_staging`.* TO 'theuser'@'localhost' WITH GRANT OPTION                               |
+------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.01 sec)

您可以尝试加载数据本地 INFILE,并使用存储在客户端磁盘中的文件。这样,您就不需要具有文件权限。它会更慢,因为文件必须上传到服务器。

希望这个帮助

首先,请向我们展示您的配置文件(my.cnf(和数据库版本。此外,连接正常的代码输出也会有所帮助。它应该是这样的:

/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'user';
/*** mysql password ***/
$password = 'pass';
function testdb_connect ($hostname, $username, $password){
    $dbh = new PDO("mysql:host=$hostname;dbname=database", $username, $password);
    return $dbh;
}
try {
    $dbh = testdb_connect ($hostname, $username, $password);
    echo 'Connected to database';
} catch(PDOException $e) {
    echo $e->getMessage();
}

至于错误:

ERROR 1045 (28000) at line 1: Access denied for user 'user'@'localhost'
and
ERROR 1148 (42000) at line 1: The used command is not allowed with this MySQL version

如果执行,是否会出现错误:

/usr/bin/mysql --host=localhost --user=theuser --password=password --database=db_database<<EOFMYSQL
show tables;
EOFMYSQL

您可以检查的一件事是(这需要您登录到MySQL控制台( - 检查以确保您有权通过localhost登录到MySQL:

mysql -h 127.0.0.1 -u user -p
mysql> select user,host from mysql.user;
+------+--------------------------------+
| user | host                           |
+------+--------------------------------+
| user | 127.0.0.1                      | 
| user | ::1                            |
| user | localhost                      | <-- Make sure you have a localhost entry for root
+------+--------------------------------+
3 rows in set (0.00 sec)

此外,您可以为您的用户检查赠款。若要列出授予用于连接到服务器的帐户的权限,可以使用以下任一语句:

SHOW GRANTS;
SHOW GRANTS FOR CURRENT_USER;
SHOW GRANTS FOR CURRENT_USER();

为了确保权限存在问题,请尝试以下操作:

sudo service mysql stop
sudo mysqld --skip-grant-tables

然后执行加载命令。

更新

至于您的配置文件,出于安全原因,您有:

[mysqld]
local-infile=0

如果在服务器或客户端中禁用了 LOAD DATA LOCAL,则尝试发出此类语句的客户端会收到以下错误消息:

ERROR 1148: The used command is not allowed with this MySQL version

您可以设置除"admin"和"root"(例如(之外的所有用户在mysql级别没有该权限,然后登录到MySQL并运行查询:

UPDATE mysql.user SET File_priv='N' WHERE user!='da_admin' AND user!='root';
FLUSH PRIVILEGES;

对于命令行,请尝试仅使用"--local-infile"而不是"--local-infile=1",并让我们知道结果。

加载数据文件

此指令用于加载位于服务器上的文件

要使用LOAD DATA INFILE,请确保:

  • 连接用户具有FILE权限。请参阅 6.2.1 MySQL 提供的权限。

  • 服务器具有足够的(文件系统(权限来读取文件。

  • 如果设置了secure_file_priv系统变量,则文件位于该目录中。服务器不会加载该目录之外的任何文件。

加载数据本地文件内

此指令用于加载位于客户端上的文件。

要使用LOAD DATA INFILE,请确保:

  • MySQL 客户端使用 -DENABLED_LOCAL_INFILE=1 编译。 没有它LOAD DATA LOCAL INFILE无法工作。

    大多数发行版都使用此标志进行编译,但有些发行版不是。这主要是手动编译MySQL的问题。

  • MySQL 服务器使用选项 --local-infile=1 启动。

    您还可以在组[mysqld]下设置local-infile=1,以便在服务器启动时自动启用它。

    没有它LOAD DATA LOCAL INFILE无法工作。

  • 选项loose-local-infile=1设置在组[client]下。这并不总是需要的,但最好确保这不是问题。

  • 要在 PHP 中使用LOAD DATA LOCAL INFILE,您需要在构造新的数据库句柄时将驱动程序选项PDO::MYSQL_ATTR_LOCAL_INFILE设置为 true。请参阅 MySQL 函数 (PDO_MYSQL(

    必须在构造新的 PDO 实例时完成。之后用PDO::setAttribute()设置它将不起作用。

有关更多详细信息,请参阅 6.1.6 加载数据本地的安全问题。

当我联系主机时,他们说我需要 FILE 权限才能执行此操作。但这是不好的做法,不建议。

好吧,你有它。您需要 FILE 权限才能执行您尝试执行的操作。实际上,无论您使用的是PHP还是bash,情况都是如此,因为特权是通过MySQL获得的。

虽然我对直截了当地说使用 FILE 特权是一种不好的做法有一些保留意见,但我确实认为存在严重的安全问题。但是,您不必授予 FILE 权限即可导入 Excel 电子表格。

我将为您提供两种解决方案,一种使用DATA INFILE,另一种不使用。

首先,注意一下:

无论是否启用FILE权限,安全可靠数据的关键是确保正确转义所有查询,尤其是那些接受用户输入的查询(下面的示例(。

DATA INFILE选项

如果您要分配FILE权限,我最担心的是黑客将能够生成各种令人讨厌的数据或提取您不希望某人拥有的数据(此处的一篇文章解释了READ LOCAL INFILE如何非常危险(。如果您的主机允许,您可以创建一个具有只能通过 localhost 访问的具有FILE权限的单独用户。虽然这绝不是灵丹妙药,但它确实大大减少了黑客访问文件的渠道,以防您确实存在注入漏洞。

CREATE USER 'filewriter'@'localhost' IDENTIFIED_BY 'some_really_long_and_complex_password';
GRANT FILE ON *.* TO 'filewriter'@'localhost';

DATA INFILE选项

请考虑此示例。

因为你使用的是PHP,我建议你创建一个PHP bash文件,或者把它放在你的脚本中,然后去掉hashbang(#!/usr/bin/php(。

你应该能够做这样的事情:

#!/usr/bin/php
$mysqli = new mysqli("host_name", "username", "password", "database") or die("Could not connect.");
$file_handle = fopen("myfile.csv", "r");

$query="INSERT into my_table_name(user_name,user_address,user_class) values(?, ?, ?)";
//practice safe escaping and store records faster.
$stmt = $mysqli->prepare($query) or die(mysql_error());
$stmt->bind_param("sss", $col1, $col2, $col3);
while (($line_of_data = fgetcsv($file_handle, 1000, ",")) !== FALSE) {
    $col1 = $line_of_data[0];
    $col2 = $line_of_data[1];
    $col3 = $line_of_data[2];
    $stmt->execute();
}
$stmt->close();

通过使用PHP,一种我认为你熟悉的语言,你将能够采取任何你需要的安全限制(我已经包含了准备好的语句(并存储你的数据。它可能不如LOAD DATA INFILE快,但这是在PHP中加载数据的安全方法。如果您的电子表格不是很大(GB(,这应该没问题。

Uncaught exception 'PDOException' with message 'SQLSTATE[28000]: Invalid authorization specification: 1045 Access denied for user 'myuser'@'localhost' (using password: YES)'

显然告诉您登录有问题,然后看看这个:

+------------------------------------------------------------------------------------------------------------------------+
| Grants for theuser@localhost                                                                                           |
+------------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'theuser'@'localhost' IDENTIFIED BY PASSWORD '*password' |
| GRANT ALL PRIVILEGES ON `mydomain_live`.* TO 'theuser'@'localhost'                                                    |
| GRANT ALL PRIVILEGES ON `mydomain_staging`.* TO 'theuser'@'localhost' WITH GRANT OPTION                               |
+------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.01 sec)

告诉你你只能访问数据库mydomain_livemydomain_staging,所以你导入脚本应该是:

#!/bin/bash
/usr/bin/mysql --host=localhost --user=theuser --password=password --database=mydomain_staging<<EOFMYSQL
LOAD DATA INFILE 'locationofmyfile.csv'
INTO TABLE test_import 
FIELDS TERMINATED BY ';'
LINES TERMINATED BY ''r'n'
IGNORE 1 LINES ( ArtID, ArtNamePharmLang, ArtNameFr, ArtNameNl, PubPrice, PercentageRebate, RebateAmount, SellingPrice, Localisation, CnkNr, EanNr, SoldQty, MinThd, MaxThd, QtyInStock, DateLastSale, VatRate, SupplierManufName, BuyPrice, InvCatCode, ArtType, ApbCatCode, ApbLegCode, PharmApbNr );
EOFMYSQL

请注意 --database=mydomain_staging

您是否尝试过从命令行使用 mysqlimport?它应该等效于在文件中加载数据:

下面是一个在客户端使用 --local 选项的示例:

mysqlimport -uTHEUSER -pPASSWORD -h ServerIPorDomainGoesHere --local --compress db_name /somepath/TableName.csv

一个重要的细节是csv文件名必须是这里的表名,请尝试一下,如果您仍然遇到相同的错误,请告诉我们。

如果 mysqlimport 不起作用,还要尝试检查匿名用户的数据库:

mysql> select user,host from mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| root             | localhost |
| root             | 127.0.0.1 |
| root             | ::1       |
|                  | localhost |
|                  | %         |
| myuser           | localhost |
+------------------+-----------+ 

尝试删除表中的那些空白用户名,因为在匹配"myuser"之前,您的登录名将与此示例中的用户名之一匹配。因此,即使对"myuser"拥有权限,匿名用户也可能没有。

希望对您有所帮助!

托管公司通常出于安全原因禁用加载数据INFILE,并建议使用加载数据本地。

这是来自Hostmonster的一个:https://my.hostmonster.com/cgi/help/317或者Bluehost的相同答案:https://my.bluehost.com/cgi/help/317

或者,您可以使用通常的fopen((,fgets((/fgetcsv((,fclose((从PHP文件中读取数据并将其插入MySQL表中。