LOAD DATA INFILE + MySQL错误28000

时间:2015-11-13 08:34:05

标签: php mysql sql csv permissions

我遇到了以下要执行的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)

更新

我试图像这样添加LOCAL:

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)

7 个答案:

答案 0 :(得分:5)

您可以尝试LOAD DATA LOCAL INFILE并使用存储在客户端磁盘中的文件。这样您就不需要拥有FILE权限。由于必须将文件上传到服务器,因此速度会慢一些。

希望这个帮助

答案 1 :(得分:4)

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

/*** 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)

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

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

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

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

然后执行LOAD命令。

<强>更新

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

[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”并让我们知道结果。

答案 2 :(得分:3)

LOAD DATA INFILE

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

要使用LOAD DATA INFILE,请确保:

  • 连接用户具有FILE权限。请参阅6.2.1 Privileges Provided by MySQL

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

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

LOAD DATA LOCAL INFILE

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

要使用LOAD DATA INFILE,请确保:

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

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

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

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

    如果没有它,

    LOAD DATA LOCAL INFILE就无法运作。

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

  • 要在 PHP 中使用LOAD DATA LOCAL INFILE,您需要在构造新的数据库句柄时将driver-option PDO::MYSQL_ATTR_LOCAL_INFILE设置为true。见MySQL Functions (PDO_MYSQL)

    构建新的PDO实例时必须完成此。之后使用PDO::setAttribute()进行设置将无效。

有关详细信息,请参阅6.1.6 Security Issues with LOAD DATA LOCAL

答案 3 :(得分:1)

  

当我联系托管时,他们说我需要FILE权限才能执行此操作。但这是不好的做法,并没有提出建议。

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

虽然我对使用FILE权限说不好的做法有所保留,但我确实认为存在严重的安全问题。但是,您不必授予导入Excel电子表格的FILE权限。

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

首先,请注意:

启用或不启用FILE权限的安全数据的关键是确保正确转义所有查询,尤其是那些接受用户输入的查询(例如下面的例子)。

DATA INFILE选项

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

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

DATA INFILE选项

考虑this示例。

因为您正在使用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),那应该没问题。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

您是否尝试过使用命令行中的mysqlimport?它应该等同于加载数据infile:

以下是在客户端使用--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”拥有权限,匿名者也可能不会。

希望它有所帮助!

答案 6 :(得分:0)

由于安全原因,托管公司通常会禁用LOAD DATA INFILE,并建议使用LOAD DATA LOCAL。

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

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