Generate CSV with fixed header with data from foreach - php

I would like to generate a CSV file with fixed header (name, email, cod) from data which is coming from a foreach loop. Here is what I tried, but it's not working yet:
$parcels = array();
$parcels = array('name','email', 'cod');
foreach ($orders as $order_id) {
$order_info = $this->model_sale_order->getOrder($order_id);
$parcels[] = $order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname'],
$parcels[] = $order_info['email'],
//if empty write null, else write value
$parcels[] = empty($this->request->post['cod'][$order_id]) ? '' : $this->request->post['cod'][$order_id],
}
$fp = fopen('php://output', 'wb');
foreach ( $parcels as $line ) {
$val = explode(",", $line);
fputcsv($fp, $val);
}
fclose($fp);

Because $line doesn't contain a "line", but a "cell".
You need a multidimensionnal array, if you want to store all data in memory before to write the file.
You could store in an array in your loop, and add it in $parcels.
$parcels = [['name','email', 'cod']]; // first line
foreach ($orders as $order_id) {
$order_info = $this->model_sale_order->getOrder($order_id);
$line = [];
$line[] = $order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname'];
$line[] = $order_info['email'];
//if empty write null, else write value
$line[] = empty($this->request->post['cod'][$order_id]) ? '' : $this->request->post['cod'][$order_id];
$parcels[] = $line; // add the line into `$parcels`
}
foreach ( $parcels as $line ) {
// no need to explode here
fputcsv($fp, $val);
}
NB: Caution, you have some , at the end of somes lines, which must be ;.
You could also do it in one loop :
$fp = fopen('php://output', 'wb');
fputcsv($fp, ['name','email', 'cod']);
foreach ($orders as $order_id)
{
$order_info = $this->model_sale_order->getOrder($order_id);
$line = [];
$line[] = $order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname'];
$line[] = $order_info['email'];
//if empty write null, else write value
$line[] = empty($this->request->post['cod'][$order_id]) ? '' : $this->request->post['cod'][$order_id];
fputcsv($fp, $line);
}
fclose($fp);
See working example

Related

fopen is duplicating the same line

I have a file that looks like this:
1||Allan||34||male||USA||||55.789.980
2||Georg||32||male||USA||||55.756.180
3||Rocky||21||male||USA||[100][200]||55.183.567
I made a function that when executed adds a given number or removes it if already present, which is $added and equals 100 for this example. This is my code:
$added = $_GET['added']; //100 for this example
$f = fopen($file, "w");
$list = file($file);
foreach ($list as $line) {
$details = explode("||", $line);
if (preg_match("~\b$details[0]\b~", 3)) {
foreach ($details as $key => $value) {
if ($key == 5) {
$newline .= str_replace("[" . $added . "]", "", $value);
} else {
$newline .= $value . "||";
}
}
$line = $newline . "\n";
}
fputs($f, $line);
}
fclose($f);
}
this code is supposed to remove the [100] from the Rocky line since its already present which it kinda does. However, upon further execution instead of adding it back it duplicates the Rocky line and messes it up so the file looks like this:
1||Allan||34||male||USA||||55.789.980
2||Georg||32||male||USA||||55.756.180
3||Rocky||21||male||USA||[100][200]55.183.567
3||Rocky||21||male||USA||[100][200]55.183.567
||
||
why is it doing this? I cant make any sense out of it...
Thank you.
First, you should read the file before you open it for output, because opening with the w mode truncates the file.
Second, you don't need to loop over the fields in $details if you just want to change one of them. Just access and assign it by index.
Then you can put the line back together with implode().
$list = file($file);
$f = fopen($file, "w");
foreach ($list as $line) {
$details = explode("||", $line);
if (preg_match("~\b$details[0]\b~", 3)) {
if (strpos("[$added]", $details[5]) === false) {
$details[5] = "[$added]" . $details[5];
} else {
$details[5] = str_replace("[$added]", "", $details[5]);
}
$line = implode('||', $details)
}
fputs($f, $line);
}
fclose($f);

How to split a php array into several parts to insert them in csv column names?

I wrote a code that allows me to read an excel file, transform it into csv and make modifications on it. I add at the end of this file 10 columns, the problem is that the name of the columns is added at once with "PICT1;PICT2; PICT3;PICT4;..." in only one column at the end of the 10. I would like each column to be called PICT1, PICT2, PICT3... How do I do this?
Currently I have this:
I would like that:
<?php
function multiSplit($string)
{
$output = array();
$cols = explode(",", $string);
foreach ($cols as $col)
{
$dashcols = explode("-", $col);
$output[] = $dashcols[0];
}
return $output;
}
//Modifications on csv file
$delimiter = $delimiterpost;
$csv_data = array();
$row = 1;
if (($handle = fopen($nomcsv, 'r')) !== FALSE) {
while (($data = fgetcsv($handle, 10000, $delimiter)) !== FALSE) {
//Add columns at the end
$data['Pictures Names'] = (!empty($data[4]) ? ($data[7] ?: '') . "_" . $data[4] . '.jpg' : '');
$data['Color-Description'] = (!empty($data[3]) ? (ltrim($data[4], '0') ?: '') . "-" . $data[3] : '');
$out = multiSplit($data[23]);
$data['PICT1'] = $out[0];
$data['PICT2'] = $out[1];
$data['PICT3'] = $out[2];
$data['PICT4'] = $out[3];
$data['PICT5'] = $out[4];
$data['PICT6'] = $out[5];
$data['PICT7'] = $out[6];
$data['PICT8'] = $out[7];
$data['PICT9'] = $out[8];
$data['PICT10'] = $out[9];
// Delete three columns
unset($data[1]);
unset($data[2]);
unset($data[3]);
//Modifications on the fourth line
if ($row == 4)
{
//All uppercase
$data = array_map('strtoupper', $data);
$data = str_replace(' *', '', $data);
$data = str_replace('/', '', $data);
//Replacement of spaces by an underscore
$data = str_replace(' ', '_', $data);
$data = str_replace('__', '_', $data);
//Replacement name by another name
$data = str_replace('STYLE_COLOR.JPG', 'PICT', $data);
$data = str_replace('COLOR-DESCRIPTION', 'COLOR_DESCRIPTION', $data);
array_filter($data, function($value) { return !is_null($value) && $value !== ''; });
for ( $i=1; $i<=10; $i++ ){
$data[] = "PICT$i";
}
}
if ($data[22])
{
$data = str_replace(',', 'ยง- ', $data);
}
$csv_data[] = $data;
$row++;
}
fclose($handle);
}
$csv_data = array_slice($csv_data, 3); // this will remove first three elements
array_pop($csv_data);// this will remove last element from array
if (($handle = fopen($nomcsv, 'w')) !== FALSE) {
foreach ($csv_data as $data) {
fputcsv($handle, $data, $delimiter);
}
fclose($handle);
}
Replace
$data[] ='PICT1'.$delimiter.'PICT2'.$delimiter.'PICT3'.$delimiter.'PICT4'.$delimiter.'PICT5'.$delimiter.'PICT6'.$delimiter.'PICT7'.$delimiter.'PICT8'.$delimiter.'PICT9'.$delimiter.'PICT10';
With a loop that creates the additional array items
// clean out any empty titles as there appear to be some at the end of the array
array_filter($data, function($value) { return !is_null($value) && $value !== ''; });
for ( $i=1; $i<=10; $i++ ){
$data[] = "PICT$i";
}

PHP script to create new csv from another csv after rearranging the data

I have a csv with following structure:
And I need the output csv as follows:
That means taking the faetures from each column and put it in the single row.
I am using php office to fetch and write the csv. I have written the following:
if ( false === $handle = fopen('../../../3b.csv', 'r') )
throw new Exception('File open failed.');
$headers = fgetcsv($handle);
$row = '';
$row = array();
$data = '';
$data = array();
while ( false !== $fields = fgetcsv($handle) ) {
$fields = array_combine($headers, $fields);
foreach($fields as $key=>$value){
if($key!='sku'){
if($value==''){
continue;
}
}
$row[$key] = $value;
}
if(sizeof($row)==1){
unset($row['sku']);
}
$row = array_filter( $row );
$data[] = $row;
}
$data = array_filter($data);
$use_keys = ['sku','AC Rating','color','Feature','Finish','Grade','Installation Location','Installation Method','Plank Style','Size','Specie','Tile Format','Warranty','Wear Layer','Width','LifeStyle',
'Material','Style','Thickness','Appearance','PEIRating','ProtectionRating'];
foreach($data as $key=>$value){
$new_arr = [];
foreach($use_keys as $apk_item) {
$new_value = '';
if (isset($data[$key][$apk_item])) {
$new_value = str_replace(",","|",$data[$key][$apk_item]);
}
$new_arr[$apk_item] = $new_value;
}
$data[$key] = $new_arr;
}
$data = array_filter($data, 'array_filter');
$final_array = array();
foreach ($data as $features) {
$product = array('feature' => '');
foreach ($features as $key => $feature) {
if ($key == 'sku') {
$product['sku'] = $feature;
}
else {
if($feature!=''){
$product['feature'] .= $key;
$product['value'] .= $feature;
}
}
}
$final_array[] = $product;
}
$final_array = array_filter($final_array);
$table = '<table border="1" id="csvtable">
<thead><tr><th>sku</th><th>feature</th><th>value</th></tr></thead>
<tbody>';
foreach($final_array as $value){
$sku = $value["sku"];
$combinedfeature = explode(",", $value['feature']);
foreach($combinedfeature as $single){
$table .= '<tr><td width="20%">'.$sku.'</td><td width="40%">'.$single['feature'].'</td><td width="40%">'.$single['value'].'</td></tr>';
}
}
$table .= '</tbody></table>';
print_r($table);
It's giving wrong output. How can I do this? Anyone can help, please?
A much more compact method would be to read the input and write out the target file in one loop.
This code reads in each line, combines it with the header and then extracts the sku (and removes it from the details). Then loops over the remaining details, and if there is a value to output it writes the output to the result file.
As each value may also be a comma separated list, this uses explode() to split them into individual items and writes them out as separate parts...
$inputFile = "a.csv";
$outputFile = "a1.csv";
$inputHandle = fopen($inputFile, 'r');
$outputHandle = fopen($outputFile, 'w');
$headers = fgetcsv($inputHandle);
fputcsv($outputHandle, ["sku", "feature", "value" ]);
while ( false !== $fields = fgetcsv($inputHandle) ) {
$fields = array_combine($headers, $fields);
$sku = $fields['sku'];
unset($fields['sku']);
foreach ( $fields as $name => $field ) {
if (!empty(trim($field))) {
$subFields = explode(",", $field );
foreach ( $subFields as $value ) {
fputcsv($outputHandle, [$sku, $name, $value]);
}
}
}
}
fclose($inputHandle);
fclose($outputHandle);

Group all lines with the same word in first column in csv

I have two columns in my csv file: first_column and second_column. I would like to group all the rows in second column into one string separated by "," if they all have the same word in the first column then output them into a text file.
first_column second_column
a Chris
a Jake
a Paula
b Anita
b Lionel
b Sheila
Desired output
a: Chris, Jake, Paula
b: Anita, Lionel, Sheila
This is what I tried. I seem to be only getting the first letter from the second_column. Any pointers would be great.
$csv_file = fopen("test.csv", "r");
$text_file = fopen("test.txt","w");
$data = array();
if ($csv_file)
{
while (($line = fgets($csv_file)) !== false)
{
$column_1 = $line[0];
$column_2 = $line[1];
if (!empty($column_1))
{
$data [$column_1] = column_2;
}
}
fclose($csv_file);
fclose($text_file);
}
else
{
// error opening the file.
}
//print_r($data);
This should work for you:
Here I first get your .csv file into an array with file(). Then I loop through each line and create an array, where the first column is the key and the second column a value of the sub array.
After this you can loop through your created array and implode() each sub array with the key to the expected line which you want. Then you can just save the data with file_put_contents() into your .txt file.
<?php
$csv_file = "test.csv";
$text_file = "test.txt";
$lines = file($csv_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
array_shift($lines);
foreach($lines as $line) {
list($key, $value) = explode(",", $line); //Change your .csv delimiter here, if you use something else than ,
$data[$key][] = $value;
}
foreach($data as $key => $arr)
$content[] = $key . ": " . implode(",", $arr) . PHP_EOL;
file_put_contents($text_file, $content);
?>
Storing result in an data array and then wring it bacj to text file should work.
$csv_file = fopen("test.csv", "r");
$text_file = fopen("test.txt","w");
$data = array();
if ($csv_file)
{
while (($line = fgets($csv_file)) !== false)
{
$column_1 = $line[0];
$column_2 = $line[1];
if (!isset($data[$column_1]))
{
$data[$column_1] = column_2
} else {
$data[$column_1] = $data[$column_1] .',' . $column_2
}
}
foreach($data as $k=>$d ){
fputs($text_file, "$k: $d") ;
}
fclose($csv_file);
fclose($text_file);
}
else
{
// error opening the file.
}

Convert csv in php and get unique value

I would like to convert a csv file that has duplicate contents and i would like to sum the quantity and extract the price without sum it.
file.csv :
code,qty,price
001,2,199
001,1,199
002,2,159
002,2,159
Actual php that sum the quantiy and get a result with unique value and total qty.
<?php
$tsvFile = new SplFileObject('file.csv');
$tsvFile->setFlags(SplFileObject::READ_CSV);
$tsvFile->setCsvControl("\t");
$file = fopen('file.csv', 'w');
$header = array('sku', 'qty');
fputcsv($file, $header, ',', '"');
foreach ($tsvFile as $line => $row) {
if ($line > 0) {
if (isset($newData[$row[0]])) {
$newData[$row[0]]+= $row[1];
} else {
$newData[$row[0]] = $row[1];
}
}
}
foreach ($newData as $key => $value) {
fputcsv($file, array($key, $value), ',', '"');
}
fclose($file);
?>
the result for this is:
code,qty
001,3
002,4
and i would like to add price, but without sum it.
The result i need is:
code,qty,price
001,3,199
002,4,159
I haven't tested this yet, but I think this is what you are looking for:
<?php
$tsvFile = new SplFileObject('file.csv');
$tsvFile->setFlags(SplFileObject::READ_CSV);
$tsvFile->setCsvControl("\t");
$file = fopen('file.csv', 'w');
$header = array('sku', 'qty');
fputcsv($file, $header, ',', '"');
foreach ($tsvFile as $line => $row) {
if ($line > 0) {
if(!isset($newData[$row[0]])) {
$newData[$row[0]] = array('qty'=>0, 'price'=>$row[2]);
}
$newData[$row[0]]['qty'] += $row[1];
}
}
foreach ($newData as $key => $arr) {
fputcsv($file, array($key, $arr['qty'], $arr['price']), ',', '"');
}
fclose($file);
?>
To start with, there's a nice function on the PHP page str_getcsv which will help you end up with a more legible array to work with:
function csv_to_array($filename='', $delimiter=',') {
if(!file_exists($filename) || !is_readable($filename))
return FALSE;
$header = NULL;
$data = array();
if (($handle = fopen($filename, 'r')) !== FALSE) {
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
}
fclose($handle);
}
return $data;
}
This is purely for legibility sake but now comes the code which would allow you to work over the array.
$aryInput = csv_to_array('file.csv', ',');
$aryTemp = array();
foreach($aryInput as $aryRow) {
if(isset($aryTemp[$aryRow['code'])) {
$aryTemp[$aryRow['code']['qty'] += $aryRow['qty'];
} else {
$aryTemp[$aryRow['code']] = $aryRow;
}
}
In the above code, it simply:
Loops through the input
Checks whether the key exists in a temporary array
If it does, it just adds the new quantity
If it doesn't, it adds the entire row
Now you can write out your expectant csv file :)

Categories