【问题标题】:Load data local infile using http:// location broken使用 http:// 位置损坏加载数据本地 infile
【发布时间】:2015-12-20 16:36:46
【问题描述】:

背景: 我将一些网站从共享主机帐户移至 VPS。除了使用来自外部服务器的数据源(即http://server1.net/getfile.php?f=101)使用 LOAD DATA LOCAL INFILE 执行查询的 php 代码行之外,一切都非常顺利。此代码在共享主机帐户上工作(并且工作了很长时间),但是,此帐户已达到资源限制,尤其是在数据库大小/速度方面。

问题: 从 http:// 地址下载的带有 LOAD DATA INFILE 的代码在移至(新)VPS 后不再起作用。

系统和软件: VPS 用作网络服务器,运行 Ubuntu (Ubuntu 14.04) 和 Vesta (0.9.8 (amd64))、apache、nginx、mysql (5.5.44)、app-armor 等。所有都是最近安装的,几乎没有更改。

从 phpinfo() 输出中选择:

System  Linux MyServer 3.13.0-62-generic #102-Ubuntu SMP Tue Aug 11 14:29:36 UTC 2015 x86_64 
Apache Version  Apache/2.4.7 (Ubuntu) mod_fcgid/2.3.9 PHP/5.5.9-1ubuntu4.11 OpenSSL/1.0.1f 
Server Root     /etc/apache2
PATH    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SERVER_SOFTWARE     Apache/2.4.7 (Ubuntu) mod_fcgid/2.3.9 PHP/5.5.9-1ubuntu4.11 OpenSSL/1.0.1f
allow_url_fopen On  On
allow_url_include   Off
doc_root    no value    
docref_ext  no value
docref_root no value
file_uploads    On
open_basedir    no value
sys_temp_dir    /tmp
upload_tmp_dir  /tmp
user_dir    no value
cURL support    enabled 
mysql
Directive                   Local Value  Master Value
mysql.allow_local_infile    On           On
mysqli
Directive                   Local Value  Master Value
mysqli.allow_local_infile   On           On

/etc/mysql/my.cnf 中的几行

[client]
loose-local-infile=1
local-infile=1

[mysqld]
basedir=/usr
datadir=/var/lib/mysql
tmpdir=/tmp
local-infile=1

以下代码与phpinfo()的文件在同一目录下运行

测试代码:

$url = "http://myserver.net/x.csv";
$file = "/var/lib/mysql/test2.csv";

$handle = curl_init($url);
curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);
/* Get the HTML or whatever is linked in $url. */
$response = curl_exec($handle);
/* Check for 404 (file not found). */
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
echo("<br>Http code: ". $httpCode);
curl_close($handle);

echo "<br>Temp_name: ". $_FILES["file"]["tmp_name"];
echo "<br>Host info: " . $conn->host_info . "\n";
echo "<br>Client info: ".mysqli_get_client_info($conn) ."\n";

$conn = mysqli_init();
if (!$conn) {
    die('mysqli_init failed');
}

if (!$conn->options(MYSQLI_OPT_LOCAL_INFILE, true)) {
    die('Setting MYSQLI_OPT_LOCAL_INFILE failed');
}

if (!$conn->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5)) {
    die('Setting MYSQLI_OPT_CONNECT_TIMEOUT failed');
}

if (!$conn->real_connect('localhost','root','pass','database')) {
    die('Connect Error (' . mysqli_connect_errno() . ') '
            . mysqli_connect_error());
}

$conn->query("LOAD DATA INFILE '". $file ."' INTO TABLE x_import (@col1) SET ID = @col1;");
echo("<br>Error file: " . mysqli_error($conn));

$conn->query("LOAD DATA INFILE '". $url ."' INTO TABLE x_import (@col1) SET ID = @col1;");
echo("<br>Error url: " . mysqli_error($conn));

$conn->query("LOAD DATA LOCAL INFILE '". $file ."' INTO TABLE x_import (@col1) SET ID = @col1;");
echo("<br>Error file (LOCAL): " . mysqli_error($conn));

$conn->query("LOAD DATA LOCAL INFILE '". $url ."' INTO TABLE x_import (@col1) SET ID = @col1;");
echo("<br>Error url (LOCAL): " . mysqli_error($conn));

$conn->query("SELECT * INTO OUTFILE 'andreas.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n' FROM x_import;");
echo("<br>Error OutFile: " . mysqli_error($conn));

代码结果:

Http code: 200
Temp_name:
Host info:
Client info: 5.5.44
Error file:
Error url: Can't get stat of '/var/lib/mysql/http:/myserver.net/x.csv' (Errcode: 2)
Error file (LOCAL): File '/var/lib/mysql/test2.csv' not found (Errcode: 13)
Error url (LOCAL): File 'http:/myserver.net/x.csv' not found (Errcode: 2)
Error OutFile: File 'andreas.txt' already exists

php 代码使用 mysql 的 root 帐户,所以那里有完全的访问/特权。

第一行sql代码(LOAD DATA INFILE without LOCAL using the local file)将文件中的数据正确添加到数据库中。

INTO OUTFILE 代码的最后一行在 /var/lib/mysql/database/ 中正确创建了一个文件(第二次给出了已经存在的错误)

从目前为止的所有研究中我了解到:

  • 错误代码 13 是权限问题。
  • 错误代码02是找不到文件。
  • “LOAD DATA”用于数据库服务器上的文件。
  • “LOAD DATA LOCAL”用于客户端上的文件(apache/php-code)。

我不明白为什么在使用 LOCAL 时 URL 中缺少 / (请参阅代码输出)。我也不明白为什么将 LOCAL 添加到 URL 时会出现错误代码 13(php 在代码的第一部分收到代码 200)。在我看来,php和mysql都无法看到正确的地方有几个原因。

下面我将解释我尝试过的许多事情的一些尝试(主要来自本网站上的大量其他答案):

我已将 /var/ 和 /var/lib/ 的文件权限更改为 755(一次更改为 777),但这并没有更改我的测试代码输出。 /tmp/ 已经设置为 777。

在 app-armor 中我已将 mysql 更改为抱怨模式,并尝试在 app-armor (usr.sbin.mysqld) 的 mysql 配置文件中进行一些更改,但两者都没有更改测试代码输出。

有用的文档(但我可能没有完全理解): http://dev.mysql.com/doc/refman/5.5/en/load-data-local.html

我更喜欢使用 LOAD DATA LOCAL 但如果它以任何其他方式工作我也很高兴。

请帮忙。欢迎提出任何问题和建议。

【问题讨论】:

    标签: php mysql file-io load-data-infile


    【解决方案1】:

    当我尝试使用mysql load infile(本地主机和远程数据库上的数据文件和项目)时遇到了同样的问题。我使用来自php 的直接mysql 命令(通过system 函数)。这是我的代码示例:

    system('mysql --local-infile -h '.$host. ' -D '.$dbname.' -u'.$dbuser.' -p'.$password." -e \"LOAD DATA LOCAL INFILE '". $pathToFile . "' INTO TABLE table FIELDS TERMINATED BY ';' (field1, field2, field3)\"");
    

    我希望这对你有用。

    【讨论】:

    • 谢谢!我认为这可能是一个很好的选择。我在我的测试设置中尝试了你的代码,但不幸的是什么也没发生。当我将 $return_val 添加到函数时,我得到一个 1(请参阅php.net/system),所以它应该做些什么,不是吗?我还使用远程访问在腻子中运行该命令,这给出了基本相同的消息:第 1 行的 ERROR 2 (HY000): File 'http://myserver2.net/x.csv' not found (Errcode: 2) .请注意,http:// 再次变为 http:/ (少一个斜线)。任何线索为什么在错误消息中更改了路径/地址?
    • 我的理由是 php 可以访问远程路径,但显然 mysql 不能(为什么会这样?)。在我看来,local-infile 变量可以阻止加载数据,我可以复制它,但我无法解决远程路径访问错误。
    • 那么,在您的主机上,您的数据库所在的位置可以尝试从远程主机获取数据文件并将其应用到数据库中,对吗?因此,您需要将文件下载到您的数据库服务器并运行 LOAD DATA INFILE 或在 myserver.net/x.csv 上运行 LOAD DATA LOCAL INFILE。有两个可用的方向 1) 本地文件 -> 本地数据库 2) 本地文件 -> 远程数据库。本地 db -> 未提供远程文件:D
    • 感谢您的建议。编写额外的 PHP 代码以供下载是一种选择。不是首选,但可能比迁移到 MariaDB 或类似的东西更容易。额外的代码将导致:远程文件 -> 本地文件 -> 本地数据库。 myserver.net 是测试环境的一部分。真实系统与第 3 方一起工作(仅访问数据),因此没有运行远程代码的选项。在迁移到 VPS 之前,情况是:远程服务器 -> 本地数据库(php 使用 localhost 连接到 mysql 并使用 LOAD DATA LOCAL INFILE)。这也是我在 VPS 上想要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2016-07-29
    • 2012-10-26
    • 1970-01-01
    相关资源
    最近更新 更多