【发布时间】: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