I'm using the php function fgetcsv() to read from a csv file. The structure of the csv file is such that, the very first row contains the data I want to import as opposed to the column title. I'd like to import from the very first row but I'm noticing that the first row is being ignored.
If I leave the first row empty, the same behavior persists. It is only when I add some dummy data in the first row's cells that the second row which contains the data I want to be imported actually gets imported and all other rows after that are imported as would be expected.
<?php
$handle = fopen($_FILES['materials']['tmp_name'], "r");
$data = fgetcsv($handle, 1000, ",");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
if($this->checkMaterialsDuplicate($data[3]) != false) {
Session::setSession('import_failure', 'The Materials for TX '.
$this->_tx_no.' have already been added.');
Helper::redirect('?section=store&subsection=import_design&page=import_design');
}
echo "<pre>";print_r($data);echo "</pre>";exit;
$this->_fields[] = 'implicit_qty_of_fittings';
$this->_values[] = $this->db->escape($data[1]);
$this->_fields[] = 'qty_of_desired_materials';
$this->_values[] = $this->db->escape($data[2]);
$this->_fields[] = 'tx_no';
$this->_values[] = $this->db->escape($data[3]);
$this->_fields[] = 'contractor_name';
$this->_values[] = $this->db->escape($data[4]);
$this->_fields[] = 'contractor_id';
$this->_values[] = $this->db->escape($data[5]);
$this->_fields[] = 'issue_date';
$this->_values[] = $this->db->escape($data[6]);
$this->_fields[] = 'due_date';
$this->_values[] = $this->db->escape($data[7]);
$this->_fields[] = 'fitting_id';
$this->_values[] = $this->db->escape($data[8]);
$this->_fields[] = 'qty_multiplied_fittings';
$this->_values[] = $this->db->escape($data[9]);
$this->_fields[] = 'imported';
$this->_values[] = 1;
$sql = "INSERT INTO `{$this->_table_6}` (`";
$sql .= implode("`, `", $this->_fields);
$sql .= "`) VALUES ('";
$sql .= implode("', '", $this->_values);
$sql .= "')";
if (!$this->db->query($sql)) {
$error[] = $sql;
}
$this->_subcontractor_name = $data[4];
$this->_subcontractor_id = $data[5];
unset($this->_fields);
unset($this->_values);
}
Link to sample csv here
You've got an extra call to fgetcsv() before the loop begins - this will be fetching the first row and then discarding it, which means the loop will start on the second row.
Just remove this line and it should work correctly
$data = fgetcsv($handle, 1000, ",");
Related
I have a simple CSV table
Name,Year of birth,City
Yeremy,1980,New York
Louis,1982,Washington
Marta,1987,Chicago
David,1985,Los Angeles
Also, I have this code to can get cell value by number of row and number of column:
$trow = 3;
$tcolumn = 3;
$output .= '<span>';
$row = 1;
$mycsvfile = array();
if (($handle = fopen($abspath, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$num = count($data);
$row++;
$mycsvfile[] = $data;.
}
fclose($handle);
}
$output .= $mycsvfile[$trowN][$tcolumnN];
$output .= '</span>';
I want to define that $trow=Marta and $tcolumn=City, so, in this case to get value "Chicago"...
The code could be optimized a lot, but with the current code:
$output .= array_column($mycsvfile, null, 0)['Marta'][2];
Re-index the array on the values in the Name (column 0)
Access the one with index Marta, getting the value in the City (column 2)
You can access by column name if you combine the column names:
if (($handle = fopen($abspath, "r")) !== FALSE) {
$columns = fgetcsv($handle, 1000, ",");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$mycsvfile[] = array_combine($columns, $data);
}
fclose($handle);
}
$output .= array_column($mycsvfile, null, 'Name')['Marta']['City'];
Keep in mind that if Marta occurs more than once in the Name column then the LAST one will be returned.
So I am importing data from an .asc file and I am putting it into a database. Everything gets inserted but in the beginning it has a little problem.
This is the code:
<?php
function importdb()
{
include('db_config.php');
$File = 'lijst.csv';
$File2 = 'preise.asc';
$handle = fopen($File, "r");
$handle2 = fopen($File2, "r");
$arrResult = array();
$arrResult2 = array();
fgetcsv($handle);
fgetcsv($handle);
fgetcsv($handle);
fgetcsv($handle);
fgetcsv($handle);
fgetcsv($handle);
while (($data = fgetcsv($handle, 1000, ";")) !== FALSE && ($data2 = fgetcsv($handle2, 1000, ";")) !== FALSE) {
//---------------------
$artikelnmr = $data[0];
$barcode = $data[1];
$omschrijving_nl = $data[2];
$omschrijving_exp = $data[3];
$bruto_prs = $data[4];
$staffel_prs = $data[5];
$aktie_prs = $data[6];
$bruto_antl = $data[8];
$staffel_antl = $data[9];
$aktie_aantal = $data[10];
$voorraad = $data[15];
$leverdatum = $data[16];
$besteld = $data[17];
$pallet_antl = $data[19];
$artikel_groep = $data[22];
$extra_info = $data[27];
//------------------------
$type = $data2[0];
$artikel = $data2[1];
$prijs1 = $data2[6];
$prijs2 = $data2[7];
$prijs3 = $data2[8];
$prijs4 = $data2[9];
$prijs5 = $data2[10];
//----------------------
$stmt = $db->prepare("INSERT INTO `producten`(`id`, `artikelnr`, `barcode`, `omschrijving_nl`, `omschrijving_exp`, `bruto_prijs`, `bruto_aant`, `staffel_prijs`, `staffel_aantal`, `aktie_prijs`, `aktie_aantal`, `voorraad`, `leverdatum`, `besteld`, `pallet_aantal`, `artikel_groep`, `extra`)
VALUES ('', :artikelnmr,:barcode,:omschrijving_nl,:omschrijving_exp,:bruto_prijs,:bruto_aantal,:staffel_prijs,:staffel_aantal,:aktie_prijs,:aktie_aantal,:voorraad,:leverdatum,:besteld,:pallet_aantal,:artikel_groep,:extra)");
$stmt2 = $db->prepare("INSERT INTO `prijzen`(`artikelnr`, `prijs_soort`, `prijs1`, `prijs2`, `prijs3`, `prijs4`, `prijs5`) VALUES (:nmr, :soort, :prijs1, :prijs2, :prijs3, :prijs4, :prijs5)");
//----------------------
$stmt->bindParam(":artikelnmr", $artikelnmr);
$stmt->bindParam(":barcode", $barcode);
$stmt->bindParam(":omschrijving_nl", $omschrijving_nl);
$stmt->bindParam(":omschrijving_exp", $omschrijving_exp);
$stmt->bindParam(":bruto_prijs", $bruto_prs);
$stmt->bindParam(":bruto_aantal", $bruto_antl);
$stmt->bindParam(":staffel_aantal", $staffel_antl);
$stmt->bindParam(":staffel_prijs", $staffel_prs);
$stmt->bindParam(":aktie_aantal", $aktie_aantal);
$stmt->bindParam(":aktie_prijs", $aktie_prs);
$stmt->bindParam(":voorraad", $voorraad);
$stmt->bindParam(":leverdatum", $leverdatum);
$stmt->bindParam(":besteld", $besteld);
$stmt->bindParam(":pallet_aantal", $pallet_antl);
$stmt->bindParam(":artikel_groep", $artikel_groep);
$stmt->bindParam(":extra", $extra_info);
//----------------------
$stmt2->bindParam("nmr", $artikel);
$stmt2->bindParam(":soort", $type);
$stmt2->bindParam(":prijs1", $prijs1);
$stmt2->bindParam(":prijs2", $prijs2);
$stmt2->bindParam(":prijs3", $prijs3);
$stmt2->bindParam(":prijs4", $prijs4);
$stmt2->bindParam(":prijs5", $prijs5);
//----------------------
$stmt2->execute();
$stmt->execute();
echo $artikel . ': ' . $type . "<br>";
}
fclose($handle);
fclose($handle2);
}
importdb();
?>
This only happens in the second statement (stmt2). Everything is okay in the first statement (stmt)
This is what happens in the database and what should be put in the first few lines:
Database Result
What should be inserted
Do I need to skip a few lines just like I did in the first file?
Thanks in advance.
I have the following code to insert records into a database via a csv file
$get_columns = $db_website->prepare("SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'mytable' AND TABLE_NAME = 'products'");
$get_columns->execute();
while ($row = $get_columns->fetch(PDO::FETCH_ASSOC)) {
$want[] = $row['COLUMN_NAME'];
}
$file = fopen($_FILES['filename']['tmp_name'], "r");
$counter = 0;
while (!feof($file)) {
if ($counter === 1)
break;
$have = fgetcsv ($file, 5000);
++$counter;
}
fclose ($file);
$map = array_intersect($have, $want);
$num_feilds = implode($map);
$fields = "`".implode("`,`",$map)."`";
if ($num_feilds != '') {
$file = fopen($_FILES['filename']['tmp_name'], "r");
$line = fgetcsv($file, 1000, ",");
while (($line = fgetcsv($file)) !== FALSE) {
$data = array_intersect_key($line, $map);
$implode = str_replace("'", ''', $data);
$implode = str_replace("£", '£', $implode);
$implode = "'".implode("','",$implode)."'";
$query = $db_website->prepare("SELECT p.stock_id
FROM products AS p
WHERE p.stock_id = :data");
$query->bindValue(':data', $data[0], PDO::PARAM_INT);
$query->execute();
$product_exists = $query->rowCount();
if ($product_exists == 0) {
$product_import = "INSERT INTO products ($fields, token, date_created) VALUES ($implode, :token, :date_created)";
$product_import = $db_website->prepare($product_import);
$product_import->execute(array(':token'=>$token, ':date_created'=>$todays_date_time));
$update_slug = "UPDATE products SET slug = LOWER(title),
slug = replace(slug, char(128), '')
WHERE token = :token";
$update_slug = $db_website->prepare($update_slug);
$update_slug->execute(array(':token'=>$token));
} else {
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$stock_id = $row['stock_id'];
$product_import = "UPDATE products SET $this_is_the_variable_i_need_to_create_from_the_implode, token = :token, date_updated = :date_updated
WHERE stock_id = :stock_id";
$product_import = $db_website->prepare($product_import);
$product_import->execute(array(':stock_id'=>$stock_id, ':token'=>$token, ':date_updated'=>$todays_date_time));
}
$update_slug = "UPDATE products SET slug = LOWER(title),
slug = replace(slug, char(128), '')
WHERE token = :token";
$update_slug = $db_website->prepare($update_slug);
$update_slug->execute(array(':token'=>$token));
}
}
fclose($file);
}
My problems lies in that I want it to update existing products as well as create new ones.
In the code above I have begun by doing a query to check whether the stock id exists and if it doesn't insert the record with an else to say update if it does.
The part I am struggling on is how do I make it implode the COLUMN_NAME and the data that is sent in the csv file.
Any tip in the right direction would be greatly appreciated.
Thank you
Dan
If I'm understanding you correctly, you need to create a series of set clauses based on what's in the $data array (which is an array containing the values from a single line of your CSV). Excluding any kind of validation (either of the columns in your import file, or the data in your import file) you could do something like this:
$sets = array();
$update_values = array();
foreach( $data as $index => $val )
{
if(empty($have[ $index ]))
continue;
$field_name = $have[ $index ];
$update_values[] = $val;
$sets[] = "{$field_name} = ':val{$index}'";
}
if( $sets )
{
$update_values[] = $stock_id;
$set_clause = implode(',',$sets);
$product_import = $db_website->prepare("UPDATE products SET {$set_clause} WHERE stock_id = :stock_id");
$product_import->execute( $update_values );
}
Again, you're going to want validate your input, but this should give you the idea.
Thank you oliakaoil,
This is the code I used in the end for anybody else who may need it in the future
$sets = array();
$update_values = array();
foreach ($data as $index => $val) {
if (empty($have[$index]))
continue;
$field_name = $have[$index];
$update_values[] = $val;
$sets[] = "{$field_name} = '{$val}'";
}
if ($sets) {
$update_values[] = $stock_id;
$set_clause = implode(',',$sets);
$product_import = "UPDATE products SET {$set_clause}, token = :token
WHERE stock_id = :stock_id";
$product_import = $db_website->prepare($product_import);
$product_import->execute(array(':stock_id'=>$update_values[0], ':token'=>$token));
}
i have a while loop which is fetching data from csv.Inside while loop there is a condition(if condition) if the condition is true foreach loop will get executed where we want to insert one row at a time into the database.This should continue for every row of the csv. if I have 10 rows in csv,it should insert all 10 rows in the database.But mycode is inserting the first row 10 times.
$handle = fopen($_FILES['upcsv']['tmp_name'], "r");
$count = count(file($_FILES['upcsv']['tmp_name']));
fgetcsv($handle, 1000, ",");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
$clt = mysql_query("select MCLNTLKNOFLG,MCLNTDKTRNGFRM,MCLNTDKTRNGTO from mclientmst where MCLNTCD ='".$data[1]."'");
if(mysql_num_rows($clt)>0)
{
$clts = mysql_fetch_array($clt);
if($clts['MCLNTLKNOFLG']==1)
{
$i=1 ;
foreach(range ($clts['MCLNTDKTRNGFRM'], $clts['MCLNTDKTRNGTO']) as $num)
{
$dkt = mysql_query("select XCMPCD from xdockethdr where XDKTNO ='$num'");
$ndkt = mysql_query("select XCMPCD from xtempdockethdr where XDKTNO ='$num'");
if(mysql_num_rows($dkt)==0 && mysql_num_rows($ndkt)==0)
{
$date = explode('/',$data[3]);
$dt = $date[2].'-'.$date[1].'-'.$date[0];
$dktid = mysql_query("select MAX(XDKTID) as maxid from xtempdockethdr");
$maxid = mysql_fetch_array($dktid);
$max = $maxid['maxid'] +1;
$query = mysql_query("insert into xtempdockethdr (XCMPCD,XCLNTCD,XDKTNO,XCNSGCD,XDKTPUDATE,XDKTPUTIME,XDKTNOPKGS,XDKTMODLV,XDKTHTOCONCD,XDKTDCTVAL,XDKTDIMWT,XDKTACTWT,XUNIQUEID,XDKTID) VALUES ('".$data[0]."','".$data[1]."','".$num."','".$data[2]."','".$dt."','".$data[4]."','".$data[5]."','".$data[6]."','".$data[7]."','".$data[8]."','".$data[9]."','".$data[10]."','".$data[11]."','".$max."')");
$i++;
}
}
}
}
}
fclose($handle);
header('Location:upload_docketentry.php');
You need to set a break; after your code.
It will close first loop (foreach) and goes down.
Add continue 2; after sql inserts.
this will end this loop and goes to the begining of while loop and continue work.
$handle = fopen($_FILES['upcsv']['tmp_name'], "r");
$count = count(file($_FILES['upcsv']['tmp_name']));
fgetcsv($handle, 1000, ",");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) // **#1 point**
{
$clt = mysql_query("select MCLNTLKNOFLG,MCLNTDKTRNGFRM,MCLNTDKTRNGTO from mclientmst where MCLNTCD ='".$data[1]."'");
if(mysql_num_rows($clt)>0)
{
$clts = mysql_fetch_array($clt);
if($clts['MCLNTLKNOFLG']==1)
{
$i=1 ;
foreach(range ($clts['MCLNTDKTRNGFRM'], $clts['MCLNTDKTRNGTO']) as $num)
{
$dkt = mysql_query("select XCMPCD from xdockethdr where XDKTNO ='$num'");
$ndkt = mysql_query("select XCMPCD from xtempdockethdr where XDKTNO ='$num'");
if(mysql_num_rows($dkt)==0 && mysql_num_rows($ndkt)==0)
{
$date = explode('/',$data[3]);
$dt = $date[2].'-'.$date[1].'-'.$date[0];
$dktid = mysql_query("select MAX(XDKTID) as maxid from xtempdockethdr");
$maxid = mysql_fetch_array($dktid);
$max = $maxid['maxid'] +1;
$query = mysql_query("insert into xtempdockethdr (XCMPCD,XCLNTCD,XDKTNO,XCNSGCD,XDKTPUDATE,XDKTPUTIME,XDKTNOPKGS,XDKTMODLV,XDKTHTOCONCD,XDKTDCTVAL,XDKTDIMWT,XDKTACTWT,XUNIQUEID,XDKTID) VALUES ('".$data[0]."','".$data[1]."','".$num."','".$data[2]."','".$dt."','".$data[4]."','".$data[5]."','".$data[6]."','".$data[7]."','".$data[8]."','".$data[9]."','".$data[10]."','".$data[11]."','".$max."')");
$i++;
// continue 2; // Goes to #1
// break; // Goes to #2
}
} // #2 point
var_dump(__LINE__); // This will executed if you place break operator
}
}
}
fclose($handle);
header('Location:upload_docketentry.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])."'";