LOAD DATA LOCAL INFILE forbidden in... PHP - php

I am trying to use LOAD DATA INFILE to insert some records into a table. Unfortunately, it's not working.
Here are some details
If I use this instruction:
LOAD DATA INFILE 'file.txt'
INTO TABLE table_ex
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(field1, field2, field3, field4);
It works using the MySQL client program and a PHP application. In this way it will look for the file in the Data Directory of my MySQL installation.
Now if I try to execute the instructions using the LOCAL option, it only works if I use the mysql client, but not from PHP:
LOAD DATA LOCAL INFILE 'path/to/file/file.txt'
INTO TABLE table_ex
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(field1, field2, field3, field4);
Again.. it works with MySQL client but not from the PHP application... I get this error:
LOAD DATA LOCAL INFILE forbidden in /path/to/my/application
I read that the problem is related to the compilation of PHP and using mysqlnd. I am using PHP 5.3.8 and MySQL 5.5.15, but I haven't found a solution.
Additional information: until now the only help I've found was an open PHP bug:

Check docs http://php.net/manual/en/ref.pdo-mysql.php.
Basically you need:
PDO::MYSQL_ATTR_LOCAL_INFILE => true
Set at instantiation.
Example:
$conn = new \PDO("mysql:host=$server;dbname=$database;", "$user", "$password", array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
));

had this problem today and solved it by setting the following in php.ini
mysqli.allow_local_infile = On

I didn't get the exact error you get, but you need no ensure the following:
Enable by adding to your my.cnf:
[mysql]
local-infile=1
[mysqld]
local-infile=1
Tell the connection in PHP that it may use LOCAL INFILE
Using mysql:
mysql_connect(server,user,code,false,128); // 128 enables LOCAL INFILE
mysql_select_db(database);
Using mysqli:
$conn = mysqli_init();
mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, true);
mysqli_real_connect($conn,server,user,code,database);
Give MySQL user FILE permission
When using LOCAL this shouldn't be necessary, though. LOCAL says that the file is located on the client server (where you have PHP is installed), otherwise it looks at server location (where MySQL is installed).
GRANT FILE ON *.* TO 'mysql_user'#'localhost'

Easier work around is to use exec()
exec("mysql -u myuser -pMyPass -e \"USE mydb;TRUNCATE mytable;LOAD DATA INFILE '" . $file . "' IGNORE INTO TABLE mytable;\"; ");

2019+ relevant answer with a bit more background:
In PHP >7.2.16 and >7.3.3 the default ini configuration of mysqli.allow_local_infile, which controls this, changed from '1' to '0' (so it is now disabled by default).
This directive is only configurable via PHP_INI_SYSTEM so ini_set() will not work.
The only option is to add the following directive to your php.ini file, not forgetting to reload apache.
[MySQLi]
mysqli.allow_local_infile = On

According to the MySQL manual MySQL must be compiled with --enable-local-infile. From a comment at that link:
You MUST have compiled PHP using the full path to MySQL, otherwise it
will use it's internal handlers, which don't work with the "new" LOAD
DATA.
--with-mysql=/usr/local/mysql (assuming your MySQL is located here)
You MUST start the MySQL daemon with the option '--local-infile=1'

The solution whish worked for me is below. Adding mysqli_options was required on second server I've setup same script.
$mysqli = new
mysqli("$db_server_name","$db_user_name","$db_password","$database_name");
// force LOCAL_INFILE
mysqli_options($mysqli, MYSQLI_OPT_LOCAL_INFILE, true);

LOAD DATA LOCAL INFILE executes regardless of the warnings. it works on mysql client since it allows the execution of queries, ignoring warnings. Though it later prints out the warnings. It refuses in PHP though because a warning will halt the script.

Easiest solution, that may work on some servers is to remove LOCAL like:
Original:LOAD DATA LOCAL INFILE
New/ It should be: LOAD DATA INFILE
Strange, but I have found this solution to work on my local machine, with xampp but it did not work on a live server with CentOS, so I'd to revert the code back and add 'LOCAL'.

I had exactly the same problem on a EC2 Ubuntu 12.04 LTS instance when accessing a MySQL on RDS: LOAD DATA LOCAL INFILE... works fine on a mysql console but not from PHP. Accidentaly i found out that it worked fine on another almost identical machine that used MariaDB (a binary compatible drop in replacement for MySQL).
So i replaced the MySQL clients with the ones from MariaDB and it worked.

If you use an Ubuntu server, you can try to install php5-mysqlnd :
sudo apt-get install php5-mysqlnd

To resolve the same problem in PHP Symfony application, this flag needs to be enabled in the yml config file. Here is an example:
# Doctrine Configuration
doctrine:
dbal:
driver: pdo_mysql
options:
!php/const PDO::MYSQL_ATTR_LOCAL_INFILE: true
# Skip the rest
Also note how to reference PHP constant here in yml file, and this format is used for Symfony 3.4. For older version, check out Symfony doc.

uncomment 'mysqli.allow_local_infile = On' in php.ini.

Related

phpmyadmin import & overwrite table

this has been annoying me for weeks and i cant find a proper solution.
im running a VPS
centos 7 (and aapanel which has no relevance)
php 7.4
mysql 5.7
phpmyadmin 5.0
ive gone into phpmyadmin, exported a table, updated 5000 rows, and i want to import and overwrite the old data into the same table.
the 'browse' and import is not an option(as vps error 503/low ram to load) and so ive tried to add it by SQL tab:
LOAD DATA LOCAL INFILE '/database/links.csv'
INTO TABLE links
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n';
with permission denied
*yes, ive added
[MySQLi]
mysqli.allow_local_infile = On
to my.conf and even tried to add to php.ini
and restarted apache and even tried removing LOCAL(Saw that on stack too) with no avail*
does anyone have an updated version, or know of a solid solution to this annoying, but should be easy solution?
EDIT
root user = fixes issue for permission denied... but...
LOAD DATA INFILE
error
#1290 - The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
--secure-file-priv has been removed from my.conf and apache restarted and error still appears
LOAD DATA LOCAL INFILE
error
#2000 - LOAD DATA LOCAL INFILE is forbidden, check mysqli.allow_local_infile
mysqli.allow_local_infile = On is still in my.conf
file has full permissions(777) and tried changing owner (www/root/mysql)
Carefully read difference between LOCAL and non-LOCAL versions of LOAD DATA command: https://dev.mysql.com/doc/refman/5.7/en/load-data.html#load-data-local
You need to check state of secure_file_priv config variable for non-LOCAL version of command:
mysql> select ##secure_file_priv;
+-----------------------+
| ##secure_file_priv |
+-----------------------+
| /var/lib/mysql-files/ |
+-----------------------+
File must be located here.
For LOCAL version of the command you must check permission of client to read such file. In case of phpmyadmin it will be php as client.
In both cases double check that mysql server or php both have enough permissions to enter directory and read file. The easiest way is to login under system user for mysql or php and just try to read file:
sudo -u mysql_or_php_user /bin/bash
or
su -s /bin/bash mysql_or_php_user
then
head /database/links.csv

LOAD DATA LOCAL INFILE is forbidden, check mysqli.allow_local_infile [duplicate]

I am trying to use LOAD DATA INFILE to insert some records into a table. Unfortunately, it's not working.
Here are some details
If I use this instruction:
LOAD DATA INFILE 'file.txt'
INTO TABLE table_ex
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(field1, field2, field3, field4);
It works using the MySQL client program and a PHP application. In this way it will look for the file in the Data Directory of my MySQL installation.
Now if I try to execute the instructions using the LOCAL option, it only works if I use the mysql client, but not from PHP:
LOAD DATA LOCAL INFILE 'path/to/file/file.txt'
INTO TABLE table_ex
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(field1, field2, field3, field4);
Again.. it works with MySQL client but not from the PHP application... I get this error:
LOAD DATA LOCAL INFILE forbidden in /path/to/my/application
I read that the problem is related to the compilation of PHP and using mysqlnd. I am using PHP 5.3.8 and MySQL 5.5.15, but I haven't found a solution.
Additional information: until now the only help I've found was an open PHP bug:
Check docs http://php.net/manual/en/ref.pdo-mysql.php.
Basically you need:
PDO::MYSQL_ATTR_LOCAL_INFILE => true
Set at instantiation.
Example:
$conn = new \PDO("mysql:host=$server;dbname=$database;", "$user", "$password", array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
));
had this problem today and solved it by setting the following in php.ini
mysqli.allow_local_infile = On
I didn't get the exact error you get, but you need no ensure the following:
Enable by adding to your my.cnf:
[mysql]
local-infile=1
[mysqld]
local-infile=1
Tell the connection in PHP that it may use LOCAL INFILE
Using mysql:
mysql_connect(server,user,code,false,128); // 128 enables LOCAL INFILE
mysql_select_db(database);
Using mysqli:
$conn = mysqli_init();
mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, true);
mysqli_real_connect($conn,server,user,code,database);
Give MySQL user FILE permission
When using LOCAL this shouldn't be necessary, though. LOCAL says that the file is located on the client server (where you have PHP is installed), otherwise it looks at server location (where MySQL is installed).
GRANT FILE ON *.* TO 'mysql_user'#'localhost'
Easier work around is to use exec()
exec("mysql -u myuser -pMyPass -e \"USE mydb;TRUNCATE mytable;LOAD DATA INFILE '" . $file . "' IGNORE INTO TABLE mytable;\"; ");
2019+ relevant answer with a bit more background:
In PHP >7.2.16 and >7.3.3 the default ini configuration of mysqli.allow_local_infile, which controls this, changed from '1' to '0' (so it is now disabled by default).
This directive is only configurable via PHP_INI_SYSTEM so ini_set() will not work.
The only option is to add the following directive to your php.ini file, not forgetting to reload apache.
[MySQLi]
mysqli.allow_local_infile = On
According to the MySQL manual MySQL must be compiled with --enable-local-infile. From a comment at that link:
You MUST have compiled PHP using the full path to MySQL, otherwise it
will use it's internal handlers, which don't work with the "new" LOAD
DATA.
--with-mysql=/usr/local/mysql (assuming your MySQL is located here)
You MUST start the MySQL daemon with the option '--local-infile=1'
The solution whish worked for me is below. Adding mysqli_options was required on second server I've setup same script.
$mysqli = new
mysqli("$db_server_name","$db_user_name","$db_password","$database_name");
// force LOCAL_INFILE
mysqli_options($mysqli, MYSQLI_OPT_LOCAL_INFILE, true);
LOAD DATA LOCAL INFILE executes regardless of the warnings. it works on mysql client since it allows the execution of queries, ignoring warnings. Though it later prints out the warnings. It refuses in PHP though because a warning will halt the script.
Easiest solution, that may work on some servers is to remove LOCAL like:
Original:LOAD DATA LOCAL INFILE
New/ It should be: LOAD DATA INFILE
Strange, but I have found this solution to work on my local machine, with xampp but it did not work on a live server with CentOS, so I'd to revert the code back and add 'LOCAL'.
I had exactly the same problem on a EC2 Ubuntu 12.04 LTS instance when accessing a MySQL on RDS: LOAD DATA LOCAL INFILE... works fine on a mysql console but not from PHP. Accidentaly i found out that it worked fine on another almost identical machine that used MariaDB (a binary compatible drop in replacement for MySQL).
So i replaced the MySQL clients with the ones from MariaDB and it worked.
If you use an Ubuntu server, you can try to install php5-mysqlnd :
sudo apt-get install php5-mysqlnd
To resolve the same problem in PHP Symfony application, this flag needs to be enabled in the yml config file. Here is an example:
# Doctrine Configuration
doctrine:
dbal:
driver: pdo_mysql
options:
!php/const PDO::MYSQL_ATTR_LOCAL_INFILE: true
# Skip the rest
Also note how to reference PHP constant here in yml file, and this format is used for Symfony 3.4. For older version, check out Symfony doc.
uncomment 'mysqli.allow_local_infile = On' in php.ini.

load data infile is not allowed MariaDB

I created a PHP script that imports posts from a CSV file into a WordPress website.
To do this, I first bulk import the posts into a table of the WP website database and then the PHP script creates the posts.
The bulk insert MYSQL query I use is the following:
load data local infile '/var/www/vhosts/sitenamehere.test/test.csv' into table test_table character set latin1 fields terminated by ';' lines terminated by '\r\n' ignore 1 lines;
When I run the script from the server I get the following error:
"the used command is not allowed with this MariaDB version for the query load data local infile..."
The problem occurs only when I execute the script from the server, in fact if I run the same query from phpMyAdmin, it lets me import the file.
Since my scripts not only imports but also updates posts, the intention was to create a cron job so that the script is executed multiple times a day. Obviously this is not possible if I keep getting the same error.
I tried adding:
the line local-infile=1 under the section [client] and [mysqld] of my.cnf
the line mysql.allow_local_infile=On under the [mysql] section of
my.cnf
the line mysql.allow_local_infile=On under the [MySQLi] section of php.ini located at /opt/plesk/php/7.1/etc
But nothing helped. Any ideas?
You must add AllowLoadLocalInfile=true; to your MySQL/MariaDB server connection string when you want to load a local file.
If using something like a LOAD LOCAL INFILE command then add --local_infile=1 to the command itself and it should work.
In recent versions of both servers this functionality is disabled by default and should only be enabled when necessary.
The guide at
https://mariadb.com/kb/en/library/load-data-infile/
says
If the local_infile system variable is set to 0, attempts to perform a LOAD DATA LOCAL will fail with an error message.
You best bet is to change the my.ini file that's being used.
Moreover the used database user needs the FILE privilege.

The used command is not allowed with this MySQL version

Alright, so after a week of trying all the different ideas answers I have found with no success, I am going to ask. This is for the LOAD DATA LOCAL INFILE, for MySQL. There have been many posts regarding this, but I am still unable to get it work from the web browser, but am able to run it from the mysql command prompt on the server, with the same user and pass connecting to the same database. What I have tried so far
MySQL version 5.5
Ubuntu 12.04
PHP version 5.3
In my.cnf
local-infile=1
in mysqld,mysql,mysql-safe
loose-local-infile=1 client
Restarted MySQL Server. At this point I was then able to run the query from the command prompt, and previously had not.
I have given the directory in which the files are being pulled from 777 access.
I have confirmed the php.ini has the local file parameter enabled.
I have updated apparmor.
Actual Query:
LOAD DATA LOCAL INFILE '/var/www/ui/uploads/r_import.csv' INTO TABLE r_data FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS (first_name,last_name,apt,user_id)
Above query works from the mysql command with no special arguments in the connection to the server.
If anyone has anymore ideas on this, I would be happy to try anything....
Thanks in advance.
<?php
include 'includes/header.php';
if($_FILES['file']['type'] != "application/vnd.ms-excel"){
die("This is not a CSV file.");
}
elseif(is_uploaded_file($_FILES['file']['tmp_name'])){
$filename = $_FILES['file']['tmp_name'];
$name = $_FILES['file']['name'];
copy( $filename, 'uploads/'.$name ) or die( "Could not copy file!");
$file_to_import = '/var/www/ui/uploads/'.$name;
$query = 'LOAD DATA LOCAL INFILE \''.$file_to_import.'\' INTO TABLE r_data FIELDS TERMINATED BY \',\' ENCLOSED BY \'"\' LINES TERMINATED BY \'\n\' IGNORE 1 ROWS (first_name,last_name,apt,user_id)';
echo $query;
$result = mysqli_query($link,$query) or die(mysqli_error($link));
}
else{
die("You shouldn't be here");
}
?>
$link = mysqli_init();
mysqli_options($link, MYSQLI_OPT_LOCAL_INFILE, true);
mysqli_real_connect($link, 'localhost', $username, $password, $database);
The connection string to the database is what worked for me. I found it in the last comment in the link given by developerwjk
Your problem is the use of the LOCAL keyword. When you use LOCAL the server expects the MySQL client to read the file and send it. This applies when the client software is running on a remote machine, or when you're running the MySQL client on the server itself. (This is why you can run your query from the server command line).
If you're running PHP there is no client software involved. PHP makes calls directly to the server, so the LOCAL keyword is invalid in this context.
To use LOAD DATA INFILE from PHP you must make sure that the file is placed in a location in the server filesystem that the MySQL server has read access to, and that the full path to that file is passed as part of your query. Don't use the LOCAL keyword.
If you're trying to load a file from a remote client you'll need to upload the file to the file system first, then execute your query.
Note this sentence from the MySQL manual: If LOCAL is specified, the file is read by the client program on the client host and sent to the server.
Reference: http://dev.mysql.com/doc/refman/5.5/en/load-data.html

LOAD DATA LOCAL INFILE fails - from php, to mysql (on Amazon rds)

We're moving our database from being on the webserver to a separate server (from an Amazon EC2 webserver to an RDS instance.)
We have a LOAD DATA INFILE that worked before that is going to need the LOCAL keyword added now that the database will be on a different machine to the webserver.
Testing on my dev server, it turns out that it doesn't work:
I can still LOAD DATA INFILE from php as I have been
I can LOAD DATA LOCAL INFILE from mysql commandline (with --local_infile=1)
I can't LOAD DATA LOCAL INFILE from php.
Between those 2 things that do work, it rules out:
problems with the sql or php code
problems with the upload file, including syntax and file permissions
mysql server settings problems
The error I get is:
ERROR 1148 (42000): The used command is not allowed with this MySQL version
(I get that error from the mysql commandline if I don't use --local_infile=1)
A few other bits of relevant info:
Ubuntu 12.04, mysql 5.5.24, php 5.3.10
I'm using php's mysql_connect (instead of mysqli, because we're planning on using facebook's hiphop compiler which doesn't support mysqli.)
Because of that, the connect command needs an extra flag set:
mysql_connect($dbHost, $dbUser, $dbPass, false, 128);
I've used phpinfo() to confirm that mysql.allow_local_infile = On
I've tried it on Amazon RDS (in case it was a problem in my dev server) and it doesn't work there either. (With the local_infile param turned on.)
The only thing I've read about that I haven't tried is to compile mysql server on my dev server with the flag turned on to allow local infile... but even if I get that working on my dev server it's not going to help me with Amazon RDS. (Besides which, LOAD DATA LOCAL INFILE does work from the mysql commandline.)
It seems like it's specifically a problem with php's mysql_connect()
Anybody using LOAD DATA LOCAL INFILE (maybe from Amazon RDS) that knows the trick to getting this to work?
I've given up on this, as I think it's a bug in php - in particular the mysql_connect code, which is now deprecated. It could probably be solved by compiling php yourself with changes to the source using steps similar to those mentioned in the bug report that #eggyal mentioned: https://bugs.php.net/bug.php?id=54158
Instead, I'm going to work around it by doing a system() call and using the mysql command line:
$sql = "LOAD DATA LOCAL INFILE '$csvPathAndFile' INTO TABLE $tableName FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\\\"' ESCAPED BY '\\\\\\\\' LINES TERMINATED BY '\\\\r\\\\n';";
system("mysql -u $dbUser -h $dbHost --password=$dbPass --local_infile=1 -e \"$sql\" $dbName");
That's working for me.
Here's a check list to rule out this nasty bug:
1- Grant the user FILE privileges in MySQL, phpMyAdmin generaly does not cover this privilege:
GRANT FILE ON *.* TO 'db_user'#'localhost';
2- Edit my.cnf in /etc/mysql/ or your mysql path:
[mysql]
local-infile=1
[mysqld]
local-infile=1
3- In php.ini at /etc/php5/cli/ or similar:
mysql.allow_local_infile = On
Optionally you can run ini_set in your script:
ini_set('mysql.allow_local_infile', 1);
4- The database handler library must use the correct options.
PDO:
new PDO('mysql:host='.$db_host.'.;dbname='.$db_name, $db_user, $db_pass,
array(PDO::MYSQL_ATTR_LOCAL_INFILE => 1));
mysqli:
$conn = mysqli_init();
mysqli_options($conn, MYSQLI_OPT_LOCAL_INFILE, true);
mysqli_real_connect($conn,server,user,code,database);
5- Make sure that the INFILE command uses the absolute path to the file and that it exists:
$sql = "LOAD DATA INFILE '".realpath(is_file($file))."'";
6- Check that the target file and parent directory are readable by PHP and by MySQL.
$ sudo chmod 777 file.csv
7- If you are working locally you can remove the LOCAL from your SQL:
LOAD DATA INFILE
Instead of:
LOAD DATA LOCAL INFILE
Note: Remember to restart the MySQL and PHP services if you edit their configuration files.
Hope this helps someone.
As referred in this post, adding 3rd and 4th parameter to mysql_connect are required to get LOAD LOCAL DATA INFILE working. It helped me. Any other suggestions (apparmor, local-infile=1 in my.cnf widely discussed in internet) did not help. Following PHP code worked for me!
mysql_connect(HOST,USER,PASS,false,128);
True, this is in manual, too.
use the following line that client activates with infile true
mysql --local-infile=1 -u root -p
If you're doing this in 2020, a tip for you is to check your phpinfo.php or php --ini for the location of the configuratin file. For me I was using virtualmin and changing the php ini file but my site had it's own specific ini file. Once I located it's location and changed it everything went back to normal.

Categories