php fputcsv and enclosing fields - php

I was just about to ask the same questions as the question aksed here.... Forcing fputcsv to Use Enclosure For *all* Fields
The question was
When I use fputcsv to write out a line
to an open file handle, PHP will add
an enclosing character to any column
that it believes needs it, but will
leave other columns without the
enclosures.
For example, you might end up with a
line like this
11,"Bob ",Jenkins,"200 main st. USA
",etc
Short of appending a bogus space to
the end of every field, is there any
way to force fputcsv to always enclose
columns with the enclosure (defaults
to a ") character?
The answer was:
No, fputcsv() only encloses the field
under the following conditions
/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (FPUTCSV_FLD_CHK(delimiter) ||
FPUTCSV_FLD_CHK(enclosure) ||
FPUTCSV_FLD_CHK(escape_char) ||
FPUTCSV_FLD_CHK('\n') ||
FPUTCSV_FLD_CHK('\r') ||
FPUTCSV_FLD_CHK('\t') ||
FPUTCSV_FLD_CHK(' ')
)
There is no "always enclose" option.
I need to create a CSV file will every field enclosed... What would be the best solution?
Thanks in advance...

Roll your own function - its not hard:
function dumbcsv($file_handle, $data_array, $enclosure, $field_sep, $record_sep)
{
dumbescape(false, $enclosure);
$data_array=array_map('dumbescape',$data_array);
return fputs($file_handle,
$enclosure
. implode($enclosure . $field_sep . $enclosure, $data_array)
. $enclosure . $record_sep);
}
function dumbescape($in, $enclosure=false)
{
static $enc;
if ($enclosure===false) {
return str_replace($enc, '\\' . $enc, $in);
}
$enc=$enclosure;
}
(above is using unix style escaping)
C.

A workaround: Supposing you have your data in a 2-dimensional array, you can append a string that will force quoting and you are sure is not contained in your data ("## ##" here) and then remove it:
$fp = fopen($filename, 'w');
foreach ($data as $line => $row) {
foreach ($row as $key => $value) {
$row[$key] = $value."## ##";
}
fputcsv($fp, $row);
}
fclose($fp);
$contents = file_get_contents($filename);
$contents = str_replace("## ##", "", $contents);
file_put_contents($filename, $contents);

I have encountered the same problem, and I have solved it as follows.
I have inserted single quotes to each array value.
This way when you open the csv file with excel, the scientific notation E + 15 will no longer be displayed.
Here I share you as I did.
This worked for me, I hope you do too.
Regards
// this function add a single quote for each member of array
function insertquote($value) {
return "'$value'";
}
# here i send each value of array
# to a insertquote function, and returns an array with new values,
# with the single quote.
foreach ($list as $ferow) {
fputcsv($fp, array_map(insertquote, $ferrow), ';');
}

Related

Remove quotes when converting array to txt file using fputcsv in PHP [duplicate]

Is there a native function or solid class/library for writing an array as a line in a CSV file without enclosures? fputcsv will default to " if nothing is passed in for the enclosure param. Google is failing me (returning results for a whole bunch of pages about fputcsv), and PEAR's libraries do more or less the same things as fputcsv.
Something that works exactly like fputcsv, but will allow the fields to remain unquoted.
currently: "field 1","field 2",field3hasNoSpaces
desired: field 1,field 2,field3hasNoSpaces
The warnings about foregoing enclosures are valid, but you've said they don't apply to your use-case.
I'm wondering why you can't just use something like this?
<?php
$fields = array(
"field 1","field 2","field3hasNoSpaces"
);
fputs(STDOUT, implode(',', $fields)."\n");
works with chr() function:
fputcsv($f,$array,',',chr(0));
fputcsv($file, $data, ';', chr(127));
Well car(0) didn't work out as the NULL value will most likely choke most csv parsers.
I ended using fputcsv() to build the initial file, then went through and removed all quotes. Elegant? Maybe not, but it got the job done :).
<?php
$filename = "sample.csv";
$handle = fopen($filename, 'w+');
fputcsv($handle, ['column 1','column 2']);
$data = ['sample','data'];
fputs($handle, implode(',', $data)."\n");
// or
fwrite($handle, implode(',', $data)."\n");
fclose($handle);
$headers = array(
'Content-Type' => 'text/csv',
);
Doesn't this work?
fputcsv($fp, split(',', $line),',',' ');
This is what I use to put standard CSV into an array...
function csv_explode($delim=',', $str, $enclose='"', $preserve=false){
$resArr = array();
$n = 0;
$expEncArr = explode($enclose, $str);
foreach($expEncArr as $EncItem){
if($n++%2){
array_push($resArr, array_pop($resArr) . ($preserve?$enclose:'') . $EncItem.($preserve?$enclose:''));
}else{
$expDelArr = explode($delim, $EncItem);
array_push($resArr, array_pop($resArr) . array_shift($expDelArr));
$resArr = array_merge($resArr, $expDelArr);
}
}
return $resArr;
}
You can then output whatever you want in a foreach loop.
The downside with a CSV file with no enclosures means an errant comma in user input will munge the row. So you'll need to remove commas before writing a CSV row.
The tricky part with handling CSV is parsing enclosures, which makes the PHP & PEAR CSV functions valuable. Essentially you're looking for a file that is comma-delimited for columns and newline-delimited for rows. Here's a simple starting point:
<?php
$col_separator= ',';
$row_separator= "\n";
$a= array(
array('my', 'values', 'are', 'awes,breakit,ome'),
array('these', 'values', 'also', "rock\nAND\nROLL")
);
function encodeRow(array $a) {
global $col_separator;
global $row_separator;
// Can't have the separators in the column data!
$a2= array();
foreach ($a as $v) {
$a2[]= str_replace(array($col_separator, $row_separator), '', $v);
}
return implode($col_separator, $a2);
}
$output= array();
foreach ($a as $row) {
$output[]= encodeRow($row);
}
echo(implode($row_separator, $output));
?>
I use tricky way to remove double quote, but only in Linux
....
fputcsv($fp, $product_data,"\t");
....
shell_exec('sed -i \'s/"//g\' /path/to/your-file.txt ');
Whats wrong with good old fwrite()?
function encloseString($field){
return ($field) ? '"' . $field . '"' : null;
}
$delimiter = ';';
$data = ["data_field_1", "data_field_2", "data_field_3"];
$fp = fopen("some-file.csv", 'w');
for($i = 0;$i<100000;$i++) {
fwrite($fp, implode($delimiter, array_map('encloseString', $data) . "\n");
}
fclose($fp);
(Obviously you need to make sure the data in $data is escaped first)
Chose the solution depends on your application. For some case own code for csv is needed. In case 1 (See result chr0), case 2 (chr127) and case 3 (chr127) the data will be modified(bad thing). Instead use something like this, thanks #oops:
<?php
$fields = array("field 1","field 2","field3hasNoSpaces");
fputs(STDOUT, implode(',', $fields)."\n");
case 1. fputcsv($f, $array, $delimiter, car(0)) See result chr0
case 2. fputcsv($f, $array, $delimiter, car(127))
chr127
case 3. fputcsv($f, $array, $delimiter, ' ')
onespace
case 4. Own code (s.above inspired by
oops or
Ansyori or
zeros-and-ones ) produces
better results.
This is an old question but as I was struggling with this as well, I thought it would be good to let anyone who is looking for something like this know than you can just pass empty string in the enclosure param of fputcsv and it will not use any enclosure at all.
i.e.
fputcsv($file, $array, ',', '');
chr(0) also worked for me:
fputcsv($fp, $aLine, $sDelimiter, chr(0));
Figured it out. By passing in the ascii code for Null to the car() function it seems to work just fine.
fputcsv($f, $array, $delimiter, car(0))
Thanks for the answers everyone!!!

php generated semicolon delimited csv showing all values in one column

I want to use different delimiters while generating CSV. When I try comma then it works fine means all values show in different columns but when I try other delimiters like ; or | then it shows all values in one column. Following code is showing all column's data in one column.
$csv_filename = $this->saveFileToDirectory.$this->fileName;
$fp = fopen ($csv_filename, "w");
fputcsv($fp, $this->headerArr);
foreach ($this->data as $key => $value) {
if(is_array($value)) {
$csvData = $this->makeStringFromArr($value);
fputcsv($fp, explode(";",$csvData),";");
}
}
fclose($fp);
$csvData value is following
"GUARANTEED AVAILABILITY;GUARANTEED AVAILABILITY;GUARANTEED
AVAILABILITY;;my;GUARANTEED AVAILABILITY
;34.5;;BLUE;80463259;VERY_GOOD;H1078;N;sss;dummy value;GUARANTEED
AVAILABILITY;"14.50, 34.50&Acirc ;°, ";GUARANTEED
AVAILABILITY;sdf"
If I replace following line then it does not show data in CSV
fputcsv($fp, $csvData,';');
Following is sample CSV
Any suggestion? What I am doing wrong or it is right and will be visible in one column when exported with other delimiters than comma?
Try this Code...
$file_handle = fopen('/var/www/demo.csv', 'w');
// save header for csv | if you want title for your column
// $header_title = ['column_1', 'column_2'];
// fputs($file_handle, implode(",", array_map("encodeFunc", $header_title)) . "\r\n");
$csv_data = ["valu1", "value12"];
fputs($file_handle, implode(",", array_map("encodeFunc", $csv_data)) . "\r\n");
fclose($file_handle);
function encodeFunc($value) {
///remove any ESCAPED double quotes within string.
$value = str_replace('\\"', '', $value);
//then force escape these same double quotes And Any UNESCAPED Ones.
$value = str_replace('"', '', $value);
//force wrap value in quotes and return
return '"' . $value . '"';
}

enclosure parameter in fputcsv not behaving as expected

This I believe has a simple explanation, I just cannot see it. I want to generate a pretty simple csv delimetered file with double quotes around field values.
As per the manual page on fputcsv(), I try to pass on the delimiter and enclosure argument explicitly to have double-quoted field values required for data import in third-party application as in function call below:
// relevant line of codes ...
while($row = mysql_fetch_array($result)){
$name_pieces = "";
$name_pieces = explode(" ", $row['name']);
$numberOfPieces = count($name_pieces);
$lastNameIndex = $numberOfPieces - 1;
$lastname = $name_pieces[$lastNameIndex];
$firstname = $name_pieces[0];
} // Line array becomes the first, second, third fields in resulting .csv output.
$line = array( $row['username'],
$row['name'],
$firstname,
$lastname,
$row['description'] );
$data[] = $line;
}
foreach($data as $dataLine){
if(fputcsv($fh, $dataLine, ',', '"') === false){
die("Unable to write to csv file.");
}
}
Following is a sample of the script's .csv output, notice that only second and last fields are quoted.
AG,"Alan Gaulois",Alan,Gaulois,"(AG) Alan Gaulois"
COMMIS,commis,commis,commis,"(COMMIS) commis"
DU,"Denis Fargo",Denis,Fargo,"(DF) Denis Fargo"
Anyone have an idea why the fields are not all quoted? I could well have missed something on doc page, any insight appreciated!
To my knowledge, yes, delimiters are only needed if there are spaces, if you need something else, consider using array_map.
Something like:
function surroundWithQuotes ($input)
{
$input = str_replace('"', '""', $input); //escaping in csv files is done by doing the same quote twice, odd
return '"' . $input . '"';
}
foreach($data as $dataLine){
if(fputcsv($fh, array_map("surroundWithQuotes" $dataLine),$dataLine, ',', '') === false){
die("Unable to write to csv file.");
}
}
the function just sets quotes, if necessary. If there is no space, special char or quote inside the string you want to write, no enclosing quotes are needed.
The $enclosure argument doesn't tell the parser "you have to quote everything", but it tells the parser, which char to use to quote (by default it is ", so you don't have to write it).
There's something missing in the above mentioned answers, the predicate or call back function would return "" in case of an empty string.
Ideally it should be.
function encloseWithQuotes($value)
{
if (empty($value)) {
return "";
}
$value = str_replace('"', '""', $value);
return '"'.$value.'"';
}

str_getcsv example

I want to parse a comma separated value string into an array. I want to try the str_getcsv() php function but I can't find any good examples on how to use it.
For example I have an input where users submit tags for programming languages (php, js, jquery, etc), like the "tags" input in stackoverflow when you submit a question.
How would I turn an input with example value="php, js, jquery" into an array using str_getcsv?
Its true that the spec at http://us3.php.net/manual/en/function.str-getcsv.php doesn't include a standard example, but the user-submitted notes do a decent job of covering it. If this is a form input:
$val = $_POST['value'];
$data = str_getcsv($val);
$data is now an array with the values. Try it and see if you have any other issues.
I think you should maybe look at explode for this task.
$values = "php, js, jquery";
$items = explode(",", $values);
// Would give you an array:
echo $items[0]; // would be php
echo $items[1]; // would be js
echo $items[2]; // would be jquery
This would probably more efficient than str_getcsv();
Note that you would need to use trim() to remove possible whitespace befores and after item values.
UPDATE:
I hadn't seen str_getcsv before, but read this quote on the manpage that would make it seem a worthwhile candidate:
Why not use explode() instead of str_getcsv() to parse rows?
Because explode() would not treat possible enclosured parts of
string or escaped characters correctly.
For simplicity and readability, I typically find myself using just explode(), only adding in str_getcsv() if the following two conditions are met: 1) the primary delimiter is also used within the data itself; 2) the token that I'm trying to use as the main delimiter is enclosed by another distinct character.
For example, a basic parser for a CSV file:
$filename = $argv[1];
if (empty($filename)) { echo "Input file required\n"; exit; }
$AccountsArray = explode("\n", file_get_contents($filename));
As long as each of the elements of $AccountsArray doesn't embed a "," within the data itself, this will work perfectly and is straightforward and easy to follow:
foreach ($AccountsArray as $entry) {
$acctArr = explode(",", $entry);
}
However, often the data will contain the delimiter, at which point an enclosing token (a " in this example) has to be present. If so, then I switch to str_getcsv() like so:
foreach ($AccountsArray as $entry) {
$acctArr = str_getcsv($entry, ",", "\"");
}
//get the csv
$csvFile = file_get_contents('test.csv');
//separate each line
$csv = explode("\n",$csvFile);
foreach ($csv as $csvLine) {
//separet each fields
$linkToInsert = explode(",",$csvLine);
//echo what you need
//$linkToInsert[0] would be the first field, $linkToInsert[1] second field, etc
echo '• ' . $linkToInsert[1] . '<br>';
}
The code is quite simple, using the Str_getcsv function, we will go
through each line of the CSV file "images.csv" that is located in the
same directory as our script.
NOTE: Functions used are compatible with versions of PHP >= 5.3.0
//First, reading the CSV file
$csvFile = file('file.csv');
foreach ($csvFile as $line) {
$url = str_getcsv($line);
$ch = curl_init($url[0]);
$name = basename($url[0]);
if (!file_exists('directory/' . $name)) {
$fp = fopen('directory/' . $name, 'wb');
}
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
}

Wrap CSV values generated by PHP fputcsv() with " "

So, my code generates a CSV file using PHP's built-in fputcsv function.
For the delimiter, I use ',' (a comma).
For the enclosure, I use '"' (a double-quote).
However, when I try something like
fputcsv($file,array('a','b',"long string, with commas",NULL,''),',','"');
it outputs
a,b,"long string, with commas",,
but I would like it to output
"a","b","long string, with commas","",""
Is there an easy way to deal with this, or would I have to write a replacement for fputcsv?
This is not usually a problem for CSV files.
fputcsv puts quotes around the value if it would be ambiguous. For example,
a,b,"long string, with commas",,
is not ambiguous, but,
a,b,long string, with commas,,
is, and will in most (read: all) cases be interpreted by the CSV reader as having more than 5 fields.
CSV parsers will accept string literals even without quotes around them.
If you want quotes around the values anyway, the following snippet would do that. It doesn't escape quotes inside the string - that exercise is left to the reader:
$row = '"' . implode('", "', $rowitems) . '"';
You would want to put this in a loop for all your rows.
I worked around this by inserting some bogus string characters, with a space, ## ##, and then removing them. Here's a sample implementation:
//$exported is our array of data to export
$filename = 'myfile.csv';
$fp = fopen($filename, 'w');
foreach ($exported as $line => $row) {
if ($line > 0) {
foreach ($row as $key => $value) {
$row[$key] = $value."## ##";
}
}
fputcsv($fp, $row);
}
fclose($fp);
$contents = file_get_contents($filename);
$contents = str_replace("## ##", "", $contents);
file_put_contents($filename, $contents);
This encloses all fields in double quotes, including empty ones
I think solution will be like this,
$order_header_arr = array("Item1", "Item2","This is Item3");
fputcsv($fp, $order_header_arr,',',' ');
remember " "[Space] Between third parameter of fputcsv
Any reason you can't str_replace(',,',',"",',$output); ? You'd also have to see if the last or first character is a comma and if so, replace the comma with ,""
fputcsv will not enclose all array variables in quotes. Having a numeric array value without quotes may be correct but presents a problem when a label or address program encounters a numeric defined US zip code because it will strip the leading zeros when printing. Thus 05123-0019 becomes 5123-19.
To enclose all values, whether they exist or not, in quotes I read the input file with fgetsrc and write a corrected version using fwrite. fgetsrc reads the record into array variables. Since fwrite writes a variable, you must string the array variables, enclose them in quotes and separate the array variable with a comma. Then add the record separator.
<?php
// fgetcsv - read array with fgetcsv and string into output variable
// then write with fwrite
// $ar is the array populated from fgetcsv and $arc is the variable strung
// with array variables enclosed in quotes and written using fwrite.
$file_in = fopen("reinOCp.csv","r") or die("Unable to open input file
reinOCp.csv!");
$file_out = fopen("printLABEL.csv", "w") or die("Unable to open output file
prtLABEL!");
while (!feof($file_in)) { //loop through each record of the input file
$ar=fgetcsv($file_in); //read the record into array $ar
if (is_array($ar)){ //this loop will string all the array values plus
// the end of record into variable $arc and then write the variable
$arc = ""; //clear variable $arc
foreach ($ar as $value) {
$arc .= '"' . $value . '",'; // add the array values, enclose in
// quotes with comma separator and store in variable $arc
}
$arc .= "\n"; //add end of record to variable $arc
fwrite($file_out, $arc) or die ("ERROR: Cannot write the file");
//write the record using variable $arc
}
}
echo "end of job";
fclose($file_in);
fclose($file_out);
?>

Categories