Insert csv data into database with single quote in data - php

if (($handle = fopen($source_file, "r")) !== FALSE) {
$columns = fgetcsv($handle, $max_line_length, ",");
foreach ($columns as &$column) {
$column = str_replace(".","",$column);
}
while (($data = fgetcsv($handle, $max_line_length, ",")) !== FALSE) {
while(count($data) < count($columns)) {
array_push($data, NULL);
}
$c = count($data);
for($i = 0; $i < $c; $i++) {
$data[$i] = "'{$data[$i]}'";
}
$sql[] = '(' . implode(',', $data) . ", '" . $_POST['custgroup'] . "'," . $_POST['user_id'] . ')';
}
$db = new PDO("mysql:host=localhost;dbname=test;","root","");
$insert = $db->prepare("INSERT INTO $target_table (". implode(',', $columns) .',custgroup,user_id) VALUES ' .implode(',', $sql));
$insert->execute();
I have a script like this which will insert csv data into database according to header,and 2 extra datas which is group and user id. It works well , but when my name in csv file is
Sher's Aria then it will have error.I know it's because of the symbol single quote in the name, ' , so what can I do to solve this problem so that any name with single quote can be inserted as well?
Thank you.
Edit:
function csv_file_to_mysql_table($source_file, $target_table, $max_line_length=10000) {
if($source_file != '')
{
if (($handle = fopen($source_file, "r")) !== FALSE) {
$columns = fgetcsv($handle, $max_line_length, ",");
$esc_columns = array();
foreach ($columns as &$column) {
$column = str_replace(".","",$column);
$esc_columns[] = escapeSqlName($column);
}
$esc_columns[] = escapeSqlName('custgroup');
$esc_columns[] = escapeSqlName('user_id');
$sqlsmttempl = 'INSERT INTO %s (%s) VALUES (%s)';
$sqlsmt = sprintf($sqlstmttempl,
escapeSqlName($target_table),
implode(',', $esc_columns),
implode(',',array_fill(0, count($esc_columns), '?')) // the parameter placeholders
);
$db = new PDO("mysql:host=localhost;dbname=test;","root","");
$insert = $db->prepare($sqlsmt);
while (($data = fgetcsv($handle, $max_line_length, ",")) !== FALSE) {
while(count($data) < count($columns)) {
$data[] = NULL;
}
$data[] = $_POST['custgroup'];
$data[] = $_POST['user_id'];
if($insert->execute($data))
{
header("Location:customer-search.php");
}
else
{
echo "no";
}
}
fclose($handle);
}
}
if (isset($_POST['submit'])) {
$file = $_FILES['filename']['tmp_name'];
$table = 'UserAddedRecord';
csv_file_to_mysql_table($file,$table);
}

You are already using PDO, so you should make PDO handle your escaping for you
with your prepared statement. The code below does that.
Note that you still have a possible security issue because you assign table
and column names dynamically. The code below attempts to make sure that won't
result in any SQL injections, but you should still be cautious.
But you won't have any problems with unescaped input to the VALUES() part,
and the insertions should be much faster since you prepare the statement
only once.
function escapeSqlName($name, $quotechar='`') {
// This is to escape column names. This $quotechar ONLY WORKS WITH MYSQL
// ANSI syntax is to use $quotechar='"' and double them where-ever " is in the table name.
return $quotechar.str_replace($quotechar, $quotechar.$quotechar, $name).$quotechar;
}
if (($handle = fopen($source_file, "r")) !== FALSE) {
$columns = fgetcsv($handle, $max_line_length, ",");
$esc_columns = array();
foreach ($columns as &$column) {
$column = str_replace(".","",$column);
$esc_columns[] = escapeSqlName($column);
}
// your two extra columns
$esc_columns[] = escapeSqlName('custgroup');
$esc_columns[] = escapeSqlName('user_id');
$sqlsmttempl = 'INSERT INTO %s (%s) VALUES (%s)';
$sqlsmt = sprintf($sqlsmttempl,
escapeSqlName($target_table), // the escaped table name
implode(',', $esc_columns), // the escaped column names
implode(',',array_fill(0, count($esc_columns), '?')) // the parameter placeholders
);
// $sqlsmt should now look like 'INSERT INTO `thetable` (`col1`,`col2`,...) VALUES (?,?,...)';
$db = new PDO("mysql:host=localhost;dbname=test;","root","");
$insert = $db->prepare($sqlsmt); // prepare statement ONCE, execute with new values MULTIPLE TIMES
while (($data = fgetcsv($handle, $max_line_length, ",")) !== FALSE) {
while(count($data) < count($columns)) {
$data[] = NULL;
}
// your two extra values
$data[] = $_POST['custgroup'];
$data[] = $_POST['user_id'];
$insert->execute($data); // does data escaping for you.
}
}

One benefit (or maybe even purpose) of prepared statments is the separation of the actual statement and its parameters (the paylod data).
Instead of building a string that contains the paylod data you should bind those parameters via PDOStatement::bindParam or PDOStatement::bindValue.

CSV escaping
Surround your fields with quotes to contain the apostrophes in a CSV file. For example in your CSV:
"title", "name"
"Mr", "O'Hara"
Database escaping
You should look at escaping your data using PDO as #VolkerK suggests.

Use
mysql_real_escape_string
for each entry in the csv file before inserting the value in the array.
so, replace
$data[$i] = "'{$data[$i]}'";
with
$data[$i] = "'".mysql_real_escape_string($data[$i])."'";

Related

while inside while runs just once

I have a problem with this code, the thing is that the inner while just runs once while the outer while does it right. What could be the problem?
Note: $producto_id is an array with ids.
$st_column = 0;
$nd_column = 1;
$posicionArray = 0;
if (($handle = fopen($ruta, "r")) != FALSE) {
fgetcsv($handle);
mysqli_query($link, "BEGIN");
while($producto_id[$posicionArray]){
$ins_producto = mysqli_query ($link, "INSERT INTO productos (encuesta_id, producto_id, nom_producto) VALUES ('".$encuesta_id."', '".$producto_id[$posicionArray]."', '".$nombre_producto[$posicionArray]."')");
while (($data = fgetcsv($handle, 0, "$delimiter")) != FALSE) {
if($producto_id[$posicionArray] == $data[$st_column]){
$ins_cupon = mysqli_query ($link, "INSERT INTO cupones (encuesta_id, producto_id, cupon, estado) VALUES ('".$encuesta_id."', '".$producto_id[$posicionArray]."', '".$data[$nd_column]."', 0)");
}
}
$posicionArray ++;
}
fclose($handle);
}
I believe you have a csv, which holds ids and coupons. It seems you are trying to go through your producto_id array and check if that exists in your CSV. This is what I would do:
CSV:
id,cupon
1,15165165
1,16516151
2,16841684
PHP:
function turn_csv_to_array($csv) {
$result = array();
if (($h = fopen($csv, "r")) != FALSE) {
$header = fgetcsv($h);
while ($row = fgetcsv($h)) {
$result[] = array_combine($header, $row);
}
fclose($h);
}
return $result;
}
$coupons = turn_csv_to_array("test.csv");
$product_ids = [1, 2, 3, 4];
foreach ($product_ids as $pid) {
// INSERT PRODUCT TO PRODUCT_DB
foreach ($coupons as $c) {
if ($pid == $c['id']) {
// INSERT PRODUCT TO COUPONS_DB
}
}
}
It all depends on what you meant by:
($data = fgetcsv($handle, 0, "$delimiter")
if you meant:
($data == fgetcsv($handle, 0, "$delimiter"))
that is the value of data is equal to the result of fgetcsv
then your code is wrong. and switch to "=="
if you mean:
($data = fgetcsv($handle, 0, "$delimiter"))
and fgetcsv can return a "0" then that is why.
using "assignments" in the middle of if statements is always bad practice.
if you do an assignment in the middle of your if statement, the value of the assignment is passed on to the boolean expression. Any value other than 0 is considered true. otherwise a 0 is considered false.

convert string to variable within prepared statement

I am creating a php script that imports a csv file into an existing mySQL database.
I am selecting the matching column headings by checking if the heading in in an array and trying to use the column number to create my input into my prepared statement.
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$numCols = count($data);
$row = array();
// process the first row to select columns for extraction
if($isFirstRow) {
$num = count($data);
for($col=0; $col<count($columns); $col++){
for($c=0; $c<$numCols; $c++)
if(!in_array($data[$c], $columns[$col])){
if($c == ($numCols-1))
{
$matchingCol[$col] = '""';
}
}
else{
$matchingCol[$col] = 'data['.$c.']';
apc_store("foo$c", $matchingCol[$col]);
}
}
$isFirstRow = false;
}
$data = array(
'contractorName' => (apc_fetch('foo1')) ,
'contractorType' => $matchingCol[3]);
$query = "INSERT INTO uploadSQL SET" . bindFields($data);
$result = $pdo->prepare($query);
$result->execute($data);
The data posted into the database is '$data[3]', '$data[5]' etc.
How can I get the INSERT to input the data stored at $data[3] and not the string '$data[3]'?
Use $data[$c] instead of 'data['.$c.']'...!?
Single quoted strings will display things almost completely "as is." Variables and most escape sequences will not be interpreted.
Not an exact solution to the problem but a work around. I'm sure there's a more efficient way.
if($isFirstRow) {
$csvRow1 = $data;
}
$num = count($data);
for($col=0; $col<count($columns); $col++){
for($c=0; $c<$numCols; $c++){
if(!in_array($csvRow1[$c], $columns[$col])){
if($c == ($numCols-1))
{
$matchingCol[$col] = '""';
}
}
else{
$matchingCol[$col] = "$data[$c]";
$c = $numCols;
}
}
}

Skipping blank rows with fopen();

I currently have some code like this:
$handle = fopen($_FILES['file']['tmp_name'], "r");
$i = 0;
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
if($i > 0) {
$sql = "
insert into TABLE(A, B, C, D)
values ('$data[0]', '$data[1]', '$data[2]', '$data[3]')
";
$stmt = $dbh -> prepare($sql);
$stmt->execute();
}
$i++;
}
fclose($handle);
This allows me to write to a certain table the contents of a CSV file, excluding the first row where all the names are. I want to be able to extract only the filled rows. How would I use so using this code?
fgetcsv returns an array consisting of a single null if the rows are empty
http://www.php.net/manual/en/function.fgetcsv.php
so you should be able to do a check based on that.
if ($data[0]===null)
{
continue;
}
or something like that
fgetcsv() returns an array with null for blank lines so you can do something like below.
$handle = fopen($_FILES['file']['tmp_name'], "r");
$i = 0;
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
if (array(null) === $data) { // ignore blank lines
continue;
}
if($i > 0) {
$sql = "
insert into TABLE(A, B, C, D)
values ('$data[0]', '$data[1]', '$data[2]', '$data[3]')
";
$stmt = $dbh -> prepare($sql);
$stmt->execute();
}
$i++;
}
fclose($handle);
Based on the documentation, fgetcsv will return an array consisting of a single null value for empty rows, so you should be able to test the return value against that and skip blank lines that way.
The following example code will skip processing blank lines. Note that I have changed the file and removed some other logic to make it more easily testable.
<?php
$handle = fopen("LocalInput.txt", "r");
$i = 0;
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
if($data== array(null)) continue;
var_dump($data);
$i++;
}
fclose($handle);
?>

How to read a value from 'x'th row and 'y'th column in CSV using PHP?

I am wondering whether it is possible to read a specific value from CSV specifed the row number and column number.
Lets say I want to read data from row number 44 and column number K?
I dont want to parse through the complete CSV. How to read specific data?
Hope I am clear with my question? Any answer would be appreciated.
CSV files have no index, so you would need at least to go to the 44th line and retrieve it:
$file = new SplFileObject($path);
$file->setFlags(SplFileObject::READ_CSV);
$single = new LimitIterator($file, $offset = 43, $limit = 1);
list($row) = iterator_to_array($single, false);
$k = 10;
echo $row[$k];
Here is a function that accepts the path to a CSV file, and inserts all records to the given MySQL table, paying attention to the column names:
<?php
function csv_file_to_mysql_table($source_file, $target_table, $max_line_length=10000) {
if (($handle = fopen("$source_file", "r")) !== FALSE) {
$columns = fgetcsv($handle, $max_line_length, ",");
foreach ($columns as &$column) {
$column = str_replace(".","",$column);
}
$insert_query_prefix = "INSERT INTO $target_table (".join(",",$columns).")\nVALUES";
while (($data = fgetcsv($handle, $max_line_length, ",")) !== FALSE) {
while (count($data)<count($columns))
array_push($data, NULL);
$query = "$insert_query_prefix (".join(",",quote_all_array($data)).");";
mysql_query($query);
}
fclose($handle);
}
}
function quote_all_array($values) {
foreach ($values as $key=>$value)
if (is_array($value))
$values[$key] = quote_all_array($value);
else
$values[$key] = quote_all($value);
return $values;
}
function quote_all($value) {
if (is_null($value))
return "NULL";
$value = "'" . mysql_real_escape_string($value) . "'";
return $value;
}
?>

Import CSV file into database

I'm using following function to import the csv file into db. All is working fine. But I'm also want its also insert $_SESSION['userid'] with CSV file. please help me. thanks
function csv_file_to_mysql_table($source_file, $target_table, $max_line_length=10000) {
if (($handle = fopen("$source_file", "r")) !== FALSE) {
$columns = fgetcsv($handle, $max_line_length, ",");
foreach ($columns as &$column) {
$column = str_replace(".","",$column);
}
$insert_query_prefix = "INSERT INTO $target_table (".join(",",$columns).")\nVALUES";
while (($data = fgetcsv($handle, $max_line_length, ",")) !== FALSE) {
while (count($data)<count($columns))
array_push($data, NULL);
$query = "$insert_query_prefix (".join(",",quote_all_array($data)).");";
mysql_query($query);
}
fclose($handle);
}
}
function quote_all_array($values) {
foreach ($values as $key=>$value)
if (is_array($value))
$values[$key] = quote_all_array($value);
else
$values[$key] = quote_all($value);
return $values;
}
function quote_all($value) {
if (is_null($value))
return "NULL";
$value = "'" . mysql_real_escape_string($value) . "'";
return $value;
}
csv_file_to_mysql_table($uploadfile,"import_csv");
echo "file is imported successfully!";
}
I imagine something like this would work. Just append the extra field after you do your array joins.
I don't know what your user_id column is called, i just assumed user_id
$insert_query_prefix = "INSERT INTO $target_table (".join(",",$columns).",user_id)\nVALUES";
add the user_id value to the values argument
$query = "$insert_query_prefix (".join(",",quote_all_array($data)).",".$_SESSION['userid'].");";
Look for "ADD HERE"... just tack the column name in after you get them and also add the data to the end of your array once its built... should be simple as that.
foreach ($columns as &$column) {
$column = str_replace(".","",$column);
}
//ADD HERE
$columns[] = "userid";
$insert_query_prefix = "INSERT INTO $target_table (".join(",",$columns).")\nVALUES";
while (($data = fgetcsv($handle, $max_line_length, ",")) !== FALSE) {
while (count($data)<count($columns))
array_push($data, NULL);
//ADD HERE
$data[] = $_SESSION['userid']
$query = "$insert_query_prefix (".join(",",quote_all_array($data)).");";
mysql_query($query);

Categories