How to fix: mysqli_query(): load data local infile forbidden - php

When trying to upload a csv file to the server, nothing is happening to the database. The errors log file shows a warning stating that: load data local infile is forbidden.
The same code runs perfectly in windows and ubuntu in localhost. But, on the server (ubunutu) things do not get working. We execute the same sql statement, as it is in php, on command line and it populates data on the database but when executing it in phpmyadmin it gives empty result.
We tried most of the solutions found on internet regarding this issue, but nothing is working: we set local-infile to true, we granted FILE to the user, we set permissions to 777, etc.
The sql statement is as follows:
...
$sql = "LOAD DATA LOCAL INFILE 'path\to\file.csv' REPLACE INTO TABLE tablename FIELDS TERMINATED BY ';' ENCLOSED '\"' LINES TERMINATED BY '\\r\\n'";
$result = mysqli_query($con, $sql);
MySQL version: 5.0.12

ANSWER:
Step1 : Open your php.ini file.
Step2 : In php.ini find [Mysqli] or you can just search it.
Step3 : Just insert mysqli.allow_local_infile = On under [Mysqli] and save it.
Job's Done!!

Related

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.

CSV upload works with local WAMP but not with remote LAMP using LOAD DATA

New:
Uploading actual .csv file to /tmp folder using WinSCP with correct structure to the server and then running LOAD DATA LOCAL INFILE from mysql CLI works flawlessly. But if you upload from the form I trigger the "sorry" error. I've echo'ed and var_dumped several global $_FILE variables and here are their results:
$_FILES['csv']['tmp_name']:
dirname is /tmp
basename is php8k4jFN (different every-time I run the script and has not .csv ending)
filename is php8k4jFN
Full Filepath:
/tmp/php8k4jFN
$_FILES['csv']['error']:
0
Permissions:
mysql and www-data are part of root group and both are allowed to read/write /tmp
Executing LOAD DATA INFILE LOCAL... from mysql CLI with a mycsv.csv file inside /tmp work fine although with some warnings(could this trigger the error?).
Removed apparmor and gave root 1775 permission t /tmp
My form lets you upload a CSV file.
I use LOAD DATA LOCAl INFILE to upload CSV's contents into a MySQL table.
Idea is: user uploads a local CSV on his computer to my remote LAMP server using my form.
If I test everything in a local environment(WAMP running on my computer) then everything works correctly. I've ironed out all the syntax, logic and CSV structure errors.
As soon as I upload my entire source to a remote LAMP server and try to upload a CSV from my laptop to it I trigger my custom error: "Sorry, couldn't upload the CSV".
I tested it and I don't get that error locally ever. Later, I had found out that I had to enable local-infile inside my.cnf under [mysqld] and [mysql] on the LAMP server to let me use LOCAL keyword.
Before I made that change I used to get: The used command is not allowed with this MySQL version.
I tried to echo the query in my PHP script and execute it manually through mysql command line and got the following error(which makes sense since the temp file doesn't exist anymore):
ERROR 2 (HY000): File '/tmp/phpINUea0' not found (Errcode: 2)
Echo'ed query:
LOAD DATA LOCAL INFILE '/tmp/phpINUea0'
INTO TABLE mydb.suites
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '\"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(suite, business_name, business_phone, business_email)
SET location_id = 2
Then I also tried to debug my form with PHP's echo, var_dump and print_r but got empty/false returns from all three statements:
$query_add_suite_csv = $this->db_connection->query($query);
echo $query_add_suite_csv; // returns nothing
var_dump($query_add_suite_csv); // returns boolean false
print_r($query_add_suite_csv); // return nothing
if ($query_add_suite_csv) {
// success message
}else{
echo "Sorry, couldn't upload the CSV"
}
Currently out of ideas as to why this could be happening. In case it matters, I've used THIS guide to setup my remote LAMP server.
File upload PHP function:
private function addSuiteCSV()
{
if (empty($_POST['suite_location_csv'])) {
$this->errors[] = "Must select location of suite";
}else{
// create a database connection
$this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if (!$this->db_connection->set_charset("utf8")) {
$this->errors[] = $this->db_connection->error;
}
if (!$this->db_connection->connect_errno) {
$suite_location_csv = $this->db_connection->real_escape_string(strip_tags($_POST['suite_location_csv'], ENT_QUOTES));
if ($_FILES['csv']['size'] > 0) {
$file = addslashes($_FILES['csv']['tmp_name']);
$query =<<<EOF
LOAD DATA LOCAL INFILE '$file'
INTO TABLE mydb.suites
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '\"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(suite, business_name, business_phone, business_email)
SET location_id = $suite_location_csv
EOF;
$query_add_suite_csv = $this->db_connection->query($query);
if ($query_add_suite_csv) {
// success
} else {
// sorry
}
}else{
// empty file
}
}else{
// db connection error
}
}
}
}
Had to move production to WAMP instead of LAMP. Must have been some unknown to me permission issue with Linux.

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

using mysql LOAD statment in PHP fails, but doing it via command line works

I have a php web page that let's a person upload a file.
I want to extract the file name from $_FILE and then load all the data into my database.
My code looks like this:
$myfile = $_FILE['file']['tmp_file'];
$executebatchloadsql = 'LOAD DATA LOCAL INFILE "'. $myfile .'" INTO TABLE testtable (fname, lname);
mysql_query($executebatchloadsql) or die(mysql_error());
But the error message I'm getting says:
The used command is not allowed with this MySQL version
My questions are as follows
Am I supposed to use the tmp_file name or the name?
What do I need to do to get the load data command to work? I've tried to follow the post found at MySQL: Enable LOAD DATA LOCAL INFILE but it's still giving me the same error.
EDIT 1:
This is what my /etc/mysql/my.cnf looks like in part:
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
local-infile
The last line is what I added. I also added the same line to the [mysql] section:
[mysql]
local-infile
After making these changes, I restarted sql:
/etc/init.d/mysql restart
But I'm still having the problem
EDIT 2:
I've also tried local-infile=1 as per the same post I mention above.
But that doesn't work either.
EDIT 3
I've tried to add the FILE prvil to the user.. like so:
GRANT FILE ON *.* TO root;
and then when i showit grants for root, i can see that its been added. but i'm still getting an error message that the used command is not allowed on my version of mysql.
Do I need the "=1" after the infile in my my.cfg file?
EDIT 4:
As a further test, i tried loading the file manually via command line instead of via php and it accepted it. I logged in as root (which is the same id i'm using my app for testing purposes) and then I tried the following command:
mysql> load data local infile '/var/www/testwebsite/abc.csv' into table testtable;
Query OK, 3 rows affected, 48 warnings (0.00 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 48
But I can't seem to get the PHP code working.
Thanks.!
After going from MySQL 5.0 to 5.5 I found out that I suddenly have to enable LOCAL INFILE specifically when creating the connection in PHP.
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);

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