简体   繁体   English

LOAD DATA INFILE + MySQL错误28000

[英]LOAD DATA INFILE + MySQL error 28000

I'm having problems with the following SQL Query I want to execute: 我遇到了以下要执行的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 );

I want to load the data of an excel file into a table in my database. 我想将excel文件的数据加载到我的数据库中的表中。 When I run this locally everything works. 当我在本地运行时一切正常。 But when I do this on the server I get the following error: 但是当我在服务器上执行此操作时,我收到以下错误:

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

I'm trying to do this in PHP (in Zend Framework). 我正在尝试用PHP(在Zend Framework中)这样做。 When I contacted the hosting they said I needed the FILE permission to do this. 当我联系托管时,他们说我需要FILE权限才能执行此操作。 But this is bad practice and not adviced. 但这是不好的做法,并没有提出建议。

I also tried to do this in a shell script like this: 我也尝试在这样的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

But I got the same error: 但我得到了同样的错误:

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

UPDATE: 更新:

I've tried to add LOCAL like this: 我试过像这样添加LOCAL:

LOAD DATA LOCAL INFILE 'thelocationofmyfile.csv'

But then I get this error: 但后来我得到了这个错误:

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

Also tried to add --local-infile=1 like this but got same error 还试图像这样添加--local-infile = 1但是得到了同样的错误

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

SECOND UPDATE: 第二次更新:

My config file my.cnf looks like this: 我的配置文件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

The location where my connection is established doesn't really matter because I'm testing it with a shell script where I make the connection. 建立连接的位置并不重要,因为我正在使用shell脚本对其进行测试,然后进行连接。

I don't get an error when I run 我跑的时候没有收到错误

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

(just a list of all the tables in my database) (只是我数据库中所有表的列表)

When I run SHOW GRANTS; 当我运行SHOW GRANTS; I get : 我明白了:

+------------------------------------------------------------------------------------------------------------------------+
| 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)

You can try LOAD DATA LOCAL INFILE and use a file stored in the client's disk. 您可以尝试LOAD DATA LOCAL INFILE并使用存储在客户端磁盘中的文件。 This way you don't need to have FILE permission. 这样您就不需要拥有FILE权限。 It will be slower since the file has to be uploaded to server. 由于必须将文件上传到服务器,因此速度会变慢。

Hope this help 希望这有帮助

To begin with, please, show us your config file (my.cnf) and verison of the database. 首先,请向我们展示您的配置文件(my.cnf)和数据库的verison。 Also, code output where connection is estableshed would be helpful. 此外,连接是estableshed的代码输出将是有帮助的。 It should be something like: 它应该是这样的:

/*** 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();
}

As for the errors: 至于错误:

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

Do you get an error if you execute: 执行时是否收到错误:

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

One thing you might check is (which requires you to login to the MySQL console) - check to make sure that you have permissions to login to MySQL via localhost: 您可能检查的一件事是(这需要您登录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)

Also, you may check GRANTS for your user. 此外,您可以检查您的用户的GRANTS。 To list the privileges granted to the account that you are using to connect to the server, you can use any of the following statements: 要列出授予用于连接服务器的帐户的权限,可以使用以下任何语句:

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

Just to be sure that there is the issue with privileges, you mat try the following: 只是为了确保存在特权问题,您可以尝试以下方法:

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

And execute LOAD command then. 然后执行LOAD命令。

UPDATE UPDATE

As for your config file, for security reasons you have: 至于您的配置文件,出于安全原因,您有:

[mysqld]
local-infile=0

If LOAD DATA LOCAL is disabled, either in the server or the client, a client that attempts to issue such a statement receives the following error message: 如果在服务器或客户端中禁用了LOAD DATA LOCAL,则尝试发出此类语句的客户端会收到以下错误消息:

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

What you can it is set all users except 'admin' and 'root' (for instance) to not have that privilege at the mysql level, then login to MySQL and run the query: 您可以将除“admin”和“root”(例如)之外的所有用户设置为在mysql级别没有该特权,然后登录MySQL并运行查询:

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

For the command line try to use only "--local-infile" insted of "--local-infile=1" and let us know the result. 对于命令行,尝试仅使用“--local-infile”的“--local-infile”,并让我们知道结果。

LOAD DATA INFILE 加载数据信息

This directive is used to load files that are located on the server . 该指令用于加载位于服务器上的文件。

To use LOAD DATA INFILE , make sure: 要使用LOAD DATA INFILE ,请确保:

  • the connecting user has the FILE privilege. 连接用户具有FILE权限。 See 6.2.1 Privileges Provided by MySQL . 请参见6.2.1 MySQL提供的权限

  • the server has sufficient (filesystem) permissions to read the file. 服务器具有足够的(文件系统)权限来读取文件。

  • that if the secure_file_priv system variable is set, the file is located in that directory. 如果设置了secure_file_priv系统变量,则该文件位于该目录中。 The server will not load any files outside of that directory. 服务器不会加载该目录之外的任何文件。

LOAD DATA LOCAL INFILE 加载数据本地信息

This directive is used to load files that are located on the client . 该指令用于加载位于客户端上的文件。

To use LOAD DATA INFILE , make sure: 要使用LOAD DATA INFILE ,请确保:

  • the MySQL client is compiled with -DENABLED_LOCAL_INFILE=1 . MySQL客户端使用-DENABLED_LOCAL_INFILE=1编译。 LOAD DATA LOCAL INFILE cannot work without it. 如果没有它, LOAD DATA LOCAL INFILE就无法工作。

    Most distributions are compiled with this flag, but some are not. 大多数发行版都使用此标志进行编译,但有些则不是。 This is mostly an issue where MySQL is compiled manually. 这主要是手动编译MySQL的问题。

  • the MySQL server is started with the option --local-infile=1 . MySQL服务器以选项--local-infile=1

    You can also set local-infile=1 under the group [mysqld] , so it is enabled automatically when the server starts. 您还可以在组[mysqld]下设置local-infile=1 ,以便在服务器启动时自动启用它。

    LOAD DATA LOCAL INFILE cannot work without it. 如果没有它, LOAD DATA LOCAL INFILE就无法工作。

  • the option loose-local-infile=1 is set under the group [client] . [client]组下设置了loose-local-infile=1选项。 This isn't always needed, but it's better to make sure this isn't an issue. 这并不总是需要,但最好确保这不是问题。

  • To use LOAD DATA LOCAL INFILE in PHP , you need to set the driver-option PDO::MYSQL_ATTR_LOCAL_INFILE to true when constructing a new database handle. 要在PHP中使用LOAD DATA LOCAL INFILE ,您需要在构造新的数据库句柄时将driver-option PDO::MYSQL_ATTR_LOCAL_INFILEtrue See MySQL Functions (PDO_MYSQL) 请参阅MySQL函数(PDO_MYSQL)

    This must be done when constructing a new PDO instance. 必须在构造新的PDO实例时完成此操作。 Setting it afterwards with PDO::setAttribute() will not work. 之后使用PDO::setAttribute()将不起作用。

See 6.1.6 Security Issues with LOAD DATA LOCAL for more details. 有关更多详细信息,请参见6.1.6 LOAD DATA LOCAL的安全问题

When I contacted the hosting they said I needed the FILE permission to do this. 当我联系托管时,他们说我需要FILE权限才能执行此操作。 But this is bad practice and not adviced. 但这是不好的做法,并没有提出建议。

Well, there you have it. 好吧,你有它。 You need FILE permissions to do what you're trying to do. 您需要FILE权限才能执行您要执行的操作。 This is actually the case regardless of whether you're using PHP or bash, because the privilege is coming through MySQL. 无论您使用的是PHP还是使用bash,实际情况都是如此,因为该权限来自MySQL。

While I have some reservations about flat-out saying it's bad practice to use the FILE privilege, I do think there are serious security concerns. 虽然我对使用FILE权限的不良做法有所保留,但我确实认为存在严重的安全问题。 However, you don't have to give FILE permission to import an Excel spreadsheet. 但是,您不必授予导入Excel电子表格的FILE权限。

I'm going to provide two solutions for you, one that uses DATA INFILE and one that doesn't. 我将为您提供两种解决方案,一种使用DATA INFILE ,另一种不使用。

First, a note: 首先,注意事项:

The key to safe and secure data with or without the FILE privilege enabled is ensuring proper escaping for ALL of your queries, especially those that accept user input (example below). 无论是否启用FILE权限,安全数据的关键是确保所有查询都能正确转义,尤其是那些接受用户输入的查询(例如下面的例子)。

The DATA INFILE option DATA INFILE选项

If you're going to assign FILE privileges, the big concern I would have would be that a hacker would be able to generate all sorts of unsavory data or pull data you don't want someone to have (an article here explains how READ LOCAL INFILE can be very dangerous). 如果你要分配FILE权限,最关心的我会是一个黑客将能够产生种种令人不快的数据,或者拉你不希望有人有数据(文章在这里介绍了如何READ LOCAL INFILE可能非常危险)。 If your host allows it, you can create a separate user with FILE permissions that is accessible only via localhost . 如果您的主机允许,您可以创建一个具有FILE权限的单独用户,该权限只能通过localhost访问。 While this is by no means a silver bullet, it does dramatically reduce the channels through which a hacker can access files in case you do have injection vulnerabilities lying around. 虽然这绝不是一个灵丹妙药,但它确实大大减少了黑客可以访问文件的渠道,以防你有注入漏洞。

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

The non- DATA INFILE option DATA INFILE选项

Consider this example. 考虑这个例子。

Because you're using PHP, I recommend you create a PHP bash file or just put it in your script and take out the hashbang ( #!/usr/bin/php ). 因为您使用的是PHP,所以我建议您创建一个PHP bash文件,或者只是将它放在脚本中并取出hashbang( #!/usr/bin/php )。

You should be able to do something like this: 你应该可以做这样的事情:

#!/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();

By using PHP, a language I assume you're comfortable with, you'll be able to take any security restrictions you need to (I included prepared statements already) and store your data. 通过使用PHP,我认为您习惯使用的语言,您将能够采取您需要的任何安全限制(我已经包含准备好的语句)并存储您的数据。 It may not be as fast as LOAD DATA INFILE , but it's a safe way to load your data in PHP. 它可能没有LOAD DATA INFILE那么快,但它是一种在PHP中加载数据的安全方式。 If your spreadsheet isn't massive (GBs) this should be just fine. 如果您的电子表格不是很大(GB),这应该没问题。

the line 这条线

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

obviously tells you got problem with your login, then look at this: 显然告诉你登录有问题,然后看看:

+------------------------------------------------------------------------------------------------------------------------+
| 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)

tells you you only have access to database mydomain_live and mydomain_staging , so you import script should be: 告诉你,你只能访问数据库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

notice the --database=mydomain_staging ? 注意--database = mydomain_staging

Have you tried using mysqlimport from the command line? 你试过从命令行使用mysqlimport吗? It should be equivalent to load data infile: 它应该等同于加载数据infile:

Here is an example with the --local option to use on the client side: 以下是在客户端使用--local选项的示例:

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

An important detail is that the csv filename must be the table name here, try it and tell us if you still get the same error. 一个重要的细节是csv文件名必须是这里的表名,尝试它并告诉我们你是否仍然得到相同的错误。

Also try to check the db for anonymous users if mysqlimport doesn't work: 如果mysqlimport不起作用,还尝试检查匿名用户的数据库:

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

Try to remove those blank usernames in the table since your login would match one of those in this example before matching "myuser". 尝试删除表中的空白用户名,因为在匹配“myuser”之前,您的登录将匹配此示例中的其中一个。 So even having permissions on "myuser" the anonymous one probably doesn't. 因此,即使对“myuser”拥有权限,匿名者也许不会。

Hope it helps! 希望能帮助到你!

Hosting companies typically disable LOAD DATA INFILE for security reasons and do suggest to use LOAD DATA LOCAL instead. 出于安全原因,托管公司通常会禁用LOAD DATA INFILE,并建议使用LOAD DATA LOCAL。

Here is one from Hostmonster: https://my.hostmonster.com/cgi/help/317 Or the same answer from Bluehost: https://my.bluehost.com/cgi/help/317 这是来自Hostmonster的一个: https//my.hostmonster.com/cgi/help/317或者来自Bluehost的相同答案: https//my.bluehost.com/cgi/help/317

Alternatively you can can just read data from the file in PHP using usual fopen(), fgets()/fgetcsv(), fclose() and insert it into MySQL table. 或者,您可以使用常用的fopen(),fgets()/ fgetcsv(),fclose()从PHP中读取文件中的数据,并将其插入MySQL表中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM