Alternative to fputcsv - php

I have an array that I want to export to a CSV file, now I know that there is a fputcsv function but I am using version 5.0.4 of PHP so this isn't an option for me.
Is there an alternative method I can use?

You can use a polyfill for this. write your code as if you where on a system that supports fputcsv From comments within the php block (with some slight framing code) but include this
(copied and slightly modified from http://www.php.net/manual/en/function.fputcsv.php#56827)
<?php
if (!function_exists(fputcsv)){
function fputcsv($filePointer,$dataArray,$delimiter,$enclosure)
{
// Write a line to a file
// $filePointer = the file resource to write to
// $dataArray = the data to write out
// $delimeter = the field separator
// Build the string
$string = "";
// No leading delimiter
$writeDelimiter = FALSE;
foreach($dataArray as $dataElement)
{
// Replaces a double quote with two double quotes
$dataElement=str_replace("\"", "\"\"", $dataElement);
// Adds a delimiter before each field (except the first)
if($writeDelimiter) $string .= $delimiter;
// Encloses each field with $enclosure and adds it to the string
$string .= $enclosure . $dataElement . $enclosure;
// Delimiters are used every time except the first.
$writeDelimiter = TRUE;
} // end foreach($dataArray as $dataElement)
// Append new line
$string .= "\n";
// Write the string to the file
fwrite($filePointer,$string);
}
}
?>

Assuming you have a $Data array, which contains individual arrays for each registry (or line), you may try this:
$Delimiter = '"';
$Separator = ','
foreach($Data as $Line)
{
fwrite($File, $Delimiter.
implode($Delimiter.$Separator.$Delimiter, $Line).$Delimiter."\n");
}
Where $File is the handle for your file. Put in $Delimiter, the character you want to put around each field, and in $Separator, the character to use between fields.

I took the solution from #Orangepill and refactored / simplified it in a couple of ways. This may also become handy if you want every field to be enclosed which is not the case in the default php implementation.
function fputcsv_custom($handle, $fields, $delimiter = ",", $enclosure = '"', $escape_char = "\\") {
$field_arr = [];
foreach($fields as $field) {
$field_arr[] = $enclosure . str_replace($enclosure, $escape_char . $enclosure, $field) . $enclosure;
}
fwrite($handle, implode($delimiter, $field_arr) . "\n");
}

Related

How to overwrite a line if starts with a specific string in PHP?

I have a text file, called logs.txt, I'm trying to create a script in PHP which is supposed to check if a string which starts with foo|| exists. If it exists, it should be replaced with a specific string, otherwise a specific string will be added at the end of the file.
This is the code I tried to make:
<?php
function replaceInFile($what, $with, $file){
$buffer = "";
$fp = file($file);
foreach($fp as $line){
$buffer .= preg_replace("|".$what."[A-Za-z_.]*|", $what.$with, $line);
}
fclose($fp);
echo $buffer;
file_put_contents($file, $buffer);
}
replaceInFile("foo||", "foo||hello", "logs.txt");
?>
but it doesn't really do what I want. Can someone help me on fixing the code? Any help is appreciated.
This should work:
$newline = preg_replace('/^' . $what . '(.*)$/', $with . '${1}', $line, 1 , $count);
$buffer .= ($count == 1) ? $newline : $line . $with;
The common Delimiters is / no | specially if you have | in your search criteria. Than you have to create a Capturing Group this is between ( and ). Now you can use this Capturing Group and in your replacement as ${ + number of the Capturing Group + }. In your case you only have one.

Can't get whitespace added to string in PHP

I"m trying to make a web form that outputs to flat text file line by line what the input to the web form is. Several of the fields are not required but the output file must input blank spaces in for whatever is not filled out. Here is what I'm trying:
$output = $_SESSION["emp_id"];
if(!empty($_POST['trans_date'])) {
$output .= $_POST["trans_date"];
}else{
$output = str_pad($output, 6);
}
if(!empty($_POST['chart'])) {
$output .= $_POST["chart"];
}else{
$output = str_pad($output, 6);
}
write_line($output);
function write_line($line){
$file = 'coh.txt';
// Open the file to get existing content
$current = file_get_contents($file);
// Append a new line to the file
$current .= $line . PHP_EOL;
// Write the contents back to the file
file_put_contents($file, $current);
}
However, when I check my output the spaces don't show up. Any ideas on what's going on with this? Thanks in advance!
str_pad is padding with spaces, not adding spaces. You're padding an existing value with spaces so that it is 6 characters long, not adding 6 whitespaces to the value. So if $_SESSION["emp_id"] is 6 characters long or more, nothing will be added.
str_pad() won't add that number of spaces, but rather makes the string that length by adding the appropriate number of spaces. Try str_repeat():
$output = $_SESSION["emp_id"];
if(!empty($_POST['trans_date'])) {
$output .= $_POST["trans_date"];
}else{
$output = $output . str_repeat(' ', 6);
}
if(!empty($_POST['chart'])) {
$output .= $_POST["chart"];
}else{
$output = $output . str_repeat(' ', 6);
}
write_line($output);
function write_line($line) {
$file = 'coh.txt';
// Open the file to get existing content
$current = file_get_contents($file);
// Append a new line to the file
$current .= $line . PHP_EOL;
// Write the contents back to the file
file_put_contents($file, $current);
}
Cheers!

including leading whitespaces when using fgets in php

I am using PHP to read a simple text file with the fgets() command:
$file = fopen("filename.txt", "r") or exit('oops');
$data = "";
while(!feof($file)) {
$data .= fgets($file) . '<br>';
}
fclose($file);
The text file has leading white spaces before the first character of each line. The fgets() is not grabbing the white spaces. Any idea why? I made sure not to use trim() on the variable. I tried this, but the leading white spaces still don't appear:
$data = str_replace(" ", " ", $data);
Not sure where to go from here.
Thanks in advance,
Doug
UPDATE:
The text appears correctly if I dump it into a textarea but not if I ECHO it to the webpage.
Function fgets() grabs the whitespaces. I don't know what you are exactly doing with the $data variable, but if you simply display it on a HTML page then you won't see whitespaces. It's because HTML strips all whitespaces. Try this code to read and show your file content:
$file = fopen('file.txt', 'r') or exit('error');
$data = '';
while(!feof($file))
{
$data .= '<pre>' . fgets($file) . '</pre><br>';
}
fclose($file);
echo $data;
The PRE tag allows you to display $data without parsing it.
Try it with:
$data = preg_replace('/\s+/', ' ', $data);
fgets should not trim whitespaces.
Try to read the file using file_get_contents it is successfully reading the whitespace in the begining of the file.
$data = file_get_contents("xyz.txt");
$data = str_replace(" ","~",$data);
echo $data;
Hope this helps
I currently have the same requirement and experienced that some characters are written as a tab character.
What i did was:
$tabChar = ' ';
$regularChar = ' '
$file = fopen('/file.txt');
while($line = fgets($file)) {
$l = str_replace("\t", $tabChar, $line);
$l = str_replace(" ", $regularChar, $line);
// ...
// replacing can be done till it matches your needs
$lines .= $l; // maybe append <br /> if neccessary
}
$result = '<pre'> . $lines . '</pre>';
This one worked for me, maybe it helps you too :-).

fputcsv and newline codes

I'm using fputcsv in PHP to output a comma-delimited file of a database query. When opening the file in gedit in Ubuntu, it looks correct - each record has a line break (no visible line break characters, but you can tell each record is separated,and opening it in OpenOffice spreadsheet allows me to view the file correctly.)
However, we're sending these files on to a client on Windows, and on their systems, the file comes in as one big, long line. Opening it in Excel, it doesn't recognize multiple lines at all.
I've read several questions on here that are pretty similar, including this one, which includes a link to the really informative Great Newline Schism explanation.
Unfortunately, we can't just tell our clients to open the files in a "smarter" editor. They need to be able to open them in Excel. Is there any programmatic way to ensure that the correct newline characters are added so the file can be opened in a spreadsheet program on any OS?
I'm already using a custom function to force quotes around all values, since fputcsv is selective about it. I've tried doing something like this:
function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){
$glue = $enclosure . $delimiter . $enclosure;
return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure."\r\n");
}
But when the file is opened in a Windows text editor, it still shows up as a single long line.
// Writes an array to an open CSV file with a custom end of line.
//
// $fp: a seekable file pointer. Most file pointers are seekable,
// but some are not. example: fopen('php://output', 'w') is not seekable.
// $eol: probably one of "\r\n", "\n", or for super old macs: "\r"
function fputcsv_eol($fp, $array, $eol) {
fputcsv($fp, $array);
if("\n" != $eol && 0 === fseek($fp, -1, SEEK_CUR)) {
fwrite($fp, $eol);
}
}
This is an improved version of #John Douthat's great answer, preserving the possibility of using custom delimiters and enclosures and returning fputcsv's original output:
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;
}
Using the php function fputcsv writes only \n and cannot be customized. This makes the function worthless for microsoft environment although some packages will detect the linux newline also.
Still the benefits of fputcsv kept me digging into a solution to replace the newline character just before sending to the file. This can be done by streaming the fputcsv to the build in php temp stream first. Then adapt the newline character(s) to whatever you want and then save to file. Like this:
function getcsvline($list, $seperator, $enclosure, $newline = "" ){
$fp = fopen('php://temp', 'r+');
fputcsv($fp, $list, $seperator, $enclosure );
rewind($fp);
$line = fgets($fp);
if( $newline and $newline != "\n" ) {
if( $line[strlen($line)-2] != "\r" and $line[strlen($line)-1] == "\n") {
$line = substr_replace($line,"",-1) . $newline;
} else {
// return the line as is (literal string)
//die( 'original csv line is already \r\n style' );
}
}
return $line;
}
/* to call the function with the array $row and save to file with filehandle $fp */
$line = getcsvline( $row, ",", "\"", "\r\n" );
fwrite( $fp, $line);
As webbiedave pointed out (thx!) probably the cleanest way is to use a stream filter.
It is a bit more complex than other solutions, but even works on streams that are not editable after writing to them (like a download using $handle = fopen('php://output', 'w'); )
Here is my approach:
class StreamFilterNewlines extends php_user_filter {
function filter($in, $out, &$consumed, $closing) {
while ( $bucket = stream_bucket_make_writeable($in) ) {
$bucket->data = preg_replace('/([^\r])\n/', "$1\r\n", $bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("newlines", "StreamFilterNewlines");
stream_filter_append($handle, "newlines");
fputcsv($handle, $list, $seperator, $enclosure);
...
alternatively, you can output in native unix format (\n only) then run unix2dos on the resulting file to convert to \r\n in the appropriate places. Just be careful that your data contains no \n's . Also, I see you are using a default separator of ~ . try a default separator of \t .
I've been dealing with a similiar situation. Here's a solution I've found that outputs CSV files with windows friendly line-endings.
http://www.php.net/manual/en/function.fputcsv.php#90883
I wasn't able to use the since I'm trying to stream a file to the client and can't use the fseeks.
windows needs \r\n as the linebreak/carriage return combo in order to show separate lines.
I did eventually get an answer over at experts-exchange; here's what worked:
function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){
$glue = $enclosure . $delimiter . $enclosure;
return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure.PHP_EOL);
}
to be used in place of standard fputcsv.

Any function to take an array of strings and return a CSV line?

I have an array of strings and want a way to create a CSV line from them. Something like:
$CSV_line = implode(',',$pieces);
Will not work as the pieces may contain comma and double quotes.
Is there a PHP built in function that takes the pieces and return a well formatted CSV line?
Thanks,
Roge
If you want to write that line to a file, you can use fputcsv
Using the streams functionnality of PHP, it should be possible to write to a variable -- indeed, there's one guy in the comments of str_getcsv who posted his implementation of str_putcsv :
<?php
function str_putcsv($input, $delimiter = ',', $enclosure = '"') {
// Open a memory "file" for read/write...
$fp = fopen('php://temp', 'r+');
// ... write the $input array to the "file" using fputcsv()...
fputcsv($fp, $input, $delimiter, $enclosure);
// ... rewind the "file" so we can read what we just wrote...
rewind($fp);
// ... read the entire line into a variable...
$data = fread($fp, 1048576); // [changed]
// ... close the "file"...
fclose($fp);
// ... and return the $data to the caller, with the trailing newline from fgets() removed.
return rtrim( $data, "\n" );
}
?>
Note : this code is not mine -- it's a copy-paste of the one posted by Ulf on php.net.
You could even write a Class to do this
class CSV_ARRAY {
static public function arr_to_csv_line($arr) {
$line = array();
foreach ($arr as $v) {
$line[] = is_array($v) ? self::arr_to_csv_line($v) : '"' . str_replace('"', '""', $v) . '"';
}
return implode(",", $line);
}
static public function arr_to_csv($arr) {
$lines = array();
foreach ($arr as $v) {
$lines[] = self::arr_to_csv_line($v);
}
return implode("\n", $lines);
}
}
you could useit like this
$csvlines = CSV_ARRAY::arr_to_csv_line($myarray);
file_put_contents($csvlines,"mycsv.csv");
thats it ;-)
As far as I know there is no such built in function. The one I'm aware of is fputcsv that does exactly what you want
but it does not return the CSV line, but writes it to a file.
<?php
$pieces = array (
'a,b,c,d', // contains comma.
'"1","2"' // contains double quotes.
);
$fp = fopen('file.csv', 'w');
fputcsv($fp, $pieces); // "a,b,c,d","""1"",""2""" written
fclose($fp);
?>
Most of the times you want create the line of CSV and write it to the file. So the above function should suffice.
I'd written one such function for PHP4 as it does not support fputcsv. I'll share it with you:
// If a value contains a comma, a quote, a space, a tab, a newline, or a linefeed,
// then surround it with quotes and replace any quotes inside it with two quotes
function make_csv_line($values)
{
// iterate through the array ele by ele.
foreach($values as $key => $value)
{
// check for presence of special char.
if ( (strpos($value, ',') !== false) || (strpos($value, '"') !== false) ||
(strpos($value, ' ') !== false) || (strpos($value, "\t") !== false) ||
(strpos($value, "\n") !== false) || (strpos($value, "\r") !== false))
{
// if present, surround the ele in quotes..also replace
// already existing " with ""
$values[$key] = '"' . str_replace('"', '""', $value) . '"';
}
}
// now create the CSV line by joining with a comma, also put a \n at the end.
return implode(',', $values) . "\n";
}
Here is a simpler fputcsv implementation:
$stdout = fopen('php://output','w'); // 'stdout' is for CLI, 'output' is for Browser
fputcsv($stdout, array('val,ue1','val"ue2','value3','etc'));
fflush($stdout); // flush for fun :)
fclose($stdout);
I snarfed this elswhere on SO and posted here for faster reference, please bump/credit the original posting:
Is my array to csv function correct?
Well, the thing is, there is no well formatted CSV. For instance, Open Office uses the semicolon (;) as default delimiter, while Excel expects it to be a comma (,). But fact is, no standard exists.
Assuming the Array looks something like this:
Array
0 => Some string
1 => Some other string, with comma
2 => And a third one with "double quotes"
);
You could either use implode with a different delimiter, e.g.
$delimiter = chr(9); // Tab
$delimiter = ';' // Semicolon. Excel's default
$delimiter = '|' // Pipe
$delimiter = "','"; // Comma plus Single Quote
If that is not working, run the String array through array_filter first and change the double quotes and comma via callback to whatever you think they should be, before exploding with just a comma delimiter:
$csv = implode(',' array_filter($array, 'my_csv_prepare'));
But keep in mind, this does not guarantee your consuming application to be able to read the CSV. It really depends on how they implemented CSV parsing. Like I said: no standard.

Categories