Related
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!!!
I am converting a Delimited FLAT file to CSV and it has some data which as comma in between them. For eg the product name Iphone 6splus, 32 gb. Since this a description of the product and can have special characters also. How do i escape the comma as because of this fputcsv is considering this data as a new line. which is wrong. I am using
$handle = fopen("data.txt", "r");
$lines = [];
$row_count=0;
if (($handle = fopen("data.txt", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, "\t")) !== FALSE) {
if($row_count>0)
{
$lines[] = $data;
}
$row_count++;
}
fclose($handle);
}
$fp = fopen('example.csv', 'w');
foreach ($lines as $line) {
fputcsv($fp, split('\*\*', $line));
}
fclose($fp);
I need to escape the value before i start converting the data and store into csv
Enclose the field in quotes, e.g.
field1_value,field2_value,"field 3,value",field4, etc...
To encode a quote, use ", a single quote symbol in a field will be encoded as "", and the whole field will become """". So if you see the following in e.g. Excel:
---------------------------------------
| regular_value |,,,"| ,"", |""" |"|
---------------------------------------
the CSV file will contain:
regular_value,",,,""",","""",","""""""",""""
A comma is simply encapsulated using quotes, so , becomes ",".
A command and quote needs to be encapsulated and quoted, so "," becomes """,""".
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.'"';
}
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);
?>
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), ';');
}