I got this great function from another post here on Stackoverflow and it worked well reading csv files into an array. But suddenly it stopped working, probably because the csv format changed. How do I get it working again?
It's:
function csvToArray($file) {
$rows = array();
$headers = array();
if (file_exists($file) && is_readable($file)) {
$handle = fopen($file, 'r');
while (!feof($handle)) {
$row = fgetcsv($handle, 10240, ',', '"');
if (empty($headers))
$headers = $row;
else if (is_array($row)) {
array_splice($row, count($headers));
$rows[] = array_combine($headers, $row);
}
}
fclose($handle);
} else {
throw new Exception($file . ' doesn`t exist or is not readable.');
}
return $rows;
}
$csv = csvToArray("import.csv");
echo '<pre>';
echo print_r($csv);
echo '</pre>';
The new CSV format is like this:
TITLE,DESCRIPTION,PRICE,CURRENCY_CODE,QUANTITY,TAGS,MATERIALS,IMAGE1,IMAGE2,IMAGE3,IMAGE4,IMAGE5,"VARIATION 1 TYPE","VARIATION 1 NAME","VARIATION 1 VALUES","VARIATION 2 TYPE","VARIATION 2 NAME","VARIATION 2 VALUES"
"Title","Description",10,USD,1,"Category", etc...
Some are in quotes, some not but all are coma separated. If the words inside "Description" also contain quotes, they are double quoted like "This is the ""greatest"" description ever".
What do I need to change to get this working again? That's so much for any tips!
UPDATE: The error I am getting is this:
PHP Warning: array_combine(): Both parameters should have an equal number of elements
Related
I'm trying to make a translation module for my web project and i hit a wall. I written two functions, one for importing the CSV data and the other for changing, deleting and adding new data to the CSV file.
Everything works like a charm except the adding part. It adds the data to the CSV file but when i want to import it in the website via PHP it doesn't display the added values. (It see that their should be values but it gives empty results in return) the function i use for reading the csv file is:
// Load in CSV (File name, delimiter, Fixed array[key,value] (optional))
function load__CSV($filename='', $delimiter=';', $fixed = null){
if(!file_exists($filename) || !is_readable($filename)) {
return FALSE;
}
$header = NULL;
$data = array();
if (($handle = fopen($filename, 'r')) !== FALSE) {
while (($row = fgetcsv($handle, 100000, $delimiter)) !== FALSE) {
if (!$header) {
$header = $row;
} else {
$data[] = array_combine($header, $row);
}
}
fclose($handle);
}
if($fixed != null) {
foreach($data as $entry){
$set_csv[$entry[''.$fixed[0].'']] = $entry[''.$fixed[1].''];
}
} else {
$set_csv = $data;
}
return $set_csv;
}
The function i use to add, edit or remove CSV content is:
// Change csv
function update__csv($csv = 'csv/language.csv',$key = array(2,''),$values = array([3,''],[4,'']),$status = 'change') {
$input = fopen(BASE_URL.$csv, 'r');
$output = fopen(BASE_URL.'csv/temporary.csv', 'w');
while (false !== ($data = fgetcsv($input, 10000, ";"))) {
if ($data[$key[0]] == $key[1]) {
foreach ($values as $value) {
$data[$value[0]] = $value[1];
}
if ($status == 'change' || $status == 'new') {
fputcsv($output, $data, ";");
}
} else {
fputcsv($output, $data, ";");
}
}
if($status == 'new'){
fputcsv($output, $values, ";");
}
fclose( $input );
fclose( $output );
unlink(BASE_URL . $csv);
rename(BASE_URL . 'csv/temporary.csv', BASE_URL . $csv);
}
If i add new values to the CSV file and then open the CSV on my PC and safe it again (without changing a thing) to CSV with UTF-8 encoding then it works as expected and loads the correct data. If i open the CSV in Notepad++ i see this difference between manual added items and php added items:
I tried other encoding methods but that is kinda new for me so i think i did something wrong. Thank you in advance for helping me!
I did find the answer after some more debugging. One value of the array didn't contain a string but a true or false statement. This meant that it didn't add the data the right way into the CSV file.
I fixed it by adding strval() to every variable before putting it into an array.
I have one excel orginal.csv file
ID Name Price
1 Xblue 12
2 Yblue 32
3 Zblue 52
And another copy.csv file
ID Name Price
1 Xblue 89
2 Yblue 43
3 Zblue 45
I want to replace rows from orginal.csv to copy.csv where ID is the same.
Can I do this manually or maybe somehow using PHP?
I search for some options on the internet, but I only found getcsv and readcsv functions that can't help me in this case. Cause this is something like updating CSV file.
It may end up in request timeout in PHP because it requires so many loops to do it. If someone can reduce the time complexity of this program then it will work. if it even works it will take a lot of time to do it.
while(! feof($f_pointer)){ //open old csv to update loop1
$ar=fgetcsv($f_pointer); // getting first row
for($i=0;$i<count($ar);$i++){ //loop2 first row array
$f_pointer2=fopen("new.csv","r"); open new csv to get data
while(! feof($f_pointer2)){ // loop3 to find ID in new csv
$ar2=fgetcsv($f_pointer2); //getting each row in array
for($j=0;$j<count($ar2);$j++){ //loop4 to compare id of old csv to new csv and update data
if($ar[i] == $ar2[j]){
foreach ($ar2 as $fields) { //loop5
fputcsv($f_pointer, $fields);
}
}
}
}
}
}
?>
I've created a little soulution. If order is important you don't have to index the array and loop through the copied array.
<?php
if(file_exists('output.csv'))
{
unlink('output.csv');
}
function fputcsv_eol($handle, $array, $delimiter = ',', $enclosure = '"', $eol = "\n") {
$return = fputcsv($handle, $array, $delimiter, $enclosure);
if($return !== FALSE && "\n" != $eol && 0 === fseek($handle, -1, SEEK_CUR)) {
fwrite($handle, $eol);
}
return $return;
}
function scanFile($sFilename, $iIndexColumn)
{
$rFile = fopen($sFilename, 'r');
$aData = array();
while(($aLine = fgetcsv($rFile)) !== false)
{
$aData[$aLine[$iIndexColumn]] = $aLine;
}
fclose($rFile);
return $aData;
}
$iIndexColumn = 0;
$iValueColum = 2;
$aOriginalData = scanFile('original.csv', 0);
$aCopyData = scanFile('copy.csv', 0);
foreach($aOriginalData as $iID => $aOriginalDatum)
{
if(array_key_exists($iID, $aCopyData))
{
$aCopyData[$iID] = $aOriginalDatum;
}
}
$rFile = fopen('output.csv', 'w');
foreach($aCopyData as $aCopyDatum)
{
fputcsv_eol($rFile, $aCopyDatum, ',', '"',"\r\n");
}
fclose($rFile);
I want to take some integers from the apriori_main table and store them into a text file as comma separated values. For each iteration I use file_put_contents to write data on the next line. Using fwrite gives the same result.
The output I want in the text file is:
1,2,3,4
But the output I'm getting is:
1
,2
,3
,4
Here is the code snippet:
$y="";
$stmt='SELECT category FROM apriori_main where id='.$id.'';
$nRows = $conn->query('select count(category) from apriori_main where id='.$id.'')->fetchColumn();
echo $nRows;
$file = "/opt/lampp/htdocs/ghi.txt";
$f = fopen($file, 'a+'); // Open in write mode
$count=1;
foreach($conn->query($stmt) as $row)
{
if($count!=$nRows)
{
$user = $row['category']."\n";
$y=$user; $y=$y.",";
$str=$y; echo $y;
$count=$count+1;
}
else
{
$user = $row['category']."\n";
$y=$user; $str=$y; echo $y;
}
file_put_contents($file, $str, FILE_APPEND);
}
fclose($f);
This is all that is needed:
$stmt = 'SELECT category FROM apriori_main where id='.$id.'';
$file = "/opt/lampp/htdocs/ghi.txt";
foreach($conn->query($stmt) as $row)
{
$str[] = $row['category'];
}
file_put_contents($file, implode(',', $str));
// only use FILE_APPEND if needed for the next time to append
Loop through query result rows
Append category to an array
Implode array elements with a comma , and write to the file
So in short, you:
Don't need to query for the count
Don't need to open the file
Don't use \n that's a newline
Don't need to add the comma , in the loop
Don't write each loop iteration
I don't know what else you're doing with these values, but you seem to have a ton of unnecessary variable declaring.
I think you can effectively break all of this
$file = "/opt/lampp/htdocs/ghi.txt";
$f = fopen($file, 'a+'); // Open in write mode
$count=1;
foreach($conn->query($stmt) as $row)
{
if($count!=$nRows)
{
$user = $row['category']."\n";
$y=$user; $y=$y.",";
$str=$y; echo $y;
$count=$count+1;
}
else
{
$user = $row['category']."\n";
$y=$user; $str=$y; echo $y;
}
file_put_contents($file, $str, FILE_APPEND);
}
fclose($f);
Down to this (with only one file operation at the end)
$file = "/opt/lampp/htdocs/ghi.txt";
foreach($conn->query($stmt) as $row)
{
$y[] = $row['category'];
}
//output to screen
echo implode("<br>", $y);
//output to file
file_put_contents($file,implode(",", $y));
I'm reading in a csv which has both ascii and UTF-8 characters and putting in into an associative array to be stored in mongo. I looked everywhere for an answer and finally came up with one. fgetcsv has issues with special characters as has been noted many times in many other posts.
For example:
Note:
Locale setting is taken into account by this function. If LANG is e.g. en_US.UTF-8, files in one-byte encoding are read wrong by this function.
None of the other solutions were working for me. I decided to go with str_getcsv instead. I wanted to post this in the hopes that this would hopefully help someone else out. Also to see if anyone else had a better solution.
Credit does need to be given to Mr.Williams and durik. Posts are here. This link was the best I found on the issue. http://www.kinghost.com.br/php/function.str-getcsv.php
$csvheader = NULL;
$data = array();
if (($handle = fopen($argv[1], "r")) !== FALSE) {
while (($row = fgets($handle, 4096)) !== FALSE) {
if (!$csvHeader) {
//format csv header row into array of strings
$row = str_replace('"', '', $row);
$row = str_replace("\r\n", '', $row);
$num = strlen($row) - strlen(str_replace(",", "", $row));
$csvHeader = array();
$csvHeader = explode( ",", $row , ($num+1) );
} else {
//line that fixed my issue
$row = utf8_encode($row);
$Data = str_getcsv($row, "\n");
foreach($Data as &$row){
$row = str_getcsv($row, ",");
$data[] = array_combine($csvHeader, $row);
}
}
}
fclose($handle);
}
example result: The value field was causing the issues.
{
"_id" : ObjectId("52932826436b1cde170041d6"),
"id" : "48",
"afdrthdrth" : "11259",
"drthdrth" : "3439428",
"fdrth" : "87",
"firht" : "COPYRIGHT",
"value" : "©2005 Junghvghme / Mugcfgnss, allcfgncfgserved",
}
I have the csv file(test.csv) and have the text as below:
1,maly,maly(),f,df
2,cheata,aaa,df,df
3,cheata,df,df,df
4,maly,fc,cfv,f
5,maly,df,fg,fg
6,chantha,fc,gf,fg
7,chantha,gh,a,g
8,David,fgfd,dfg,g
What I want:
I want to diplay only:maly cheata chantha David.For the name that have two or more the same,take only one.And I have the php code as below:
$c=0;
$data=fopen('test.csv','r');
while($row=fgets($data)){
if($c!=0){
echo $row[3]."<br>\n";
}
$c++;
}
The problem is
It does not display what I want. It displays
h h a a h h a
How do I fix this?
Use fgetcsv instead of fgets.
if (($handle = fopen("test.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
if (isset($data[1])) {
echo $data[1] . "<br>\n";
}
}
fclose($handle);
}
It looks like you were intending to call fgetcsv instead of fgets. Also, the name index would be 1 then, instead of 3:
<?php
$file = fopen('test.csv', 'r');
while($row = fgetcsv($file)) {
if (isset($row[1])) {
echo $row[1], "\n";
}
}
fclose($file);
The file method returns all lines in an array. The explode method splits up a line by a particular delimiter.
$lines = file($file_name);
$fields = array();
foreach ($lines as $line) {
$cells = explode(',', $line);
$fields[] = $cells[1];
}
echo "<pre>";
print_r($fields);
echo "</pre>";
You're heading does not match your question, you want the second column, not row.
Firstly, your getting the 4th character of each row you need to do something like this (not tested):
$data=fopen('test.csv','r');
while($row=fgets($data)){
$cols = explode(',' $row);
echo $cols[1]."<br>\n";
}