I recently needed an fputcsv() with a couple of modifications (I needed fields quoted unconditionally, and more than one character in the delimiter field). I looked at a couple of versions from the man page comments, but they were buggy in one way or another, and PHP4-specific.
The function below is as close as I can get to fputcsv()’s behaviour. I’m throwing it out there in the hope that it will be useful to someone, someday. It should be easy enough to modify to suit specific requirements.
/**
* myfputcsv()
*
* Mimics the observed behaviour of PHP's fputcsv()
*
* Requires at least PHP 5.2.0 due to reliance on __toString
*
* @param resource $fp valid file pointer
* @param array $fields array of values
* @param string $delimiter optional parameter sets the field delimiter character. Defaults to ','
* @param string $enclosure optional parameter sets the field enclosure character. Defaults to '"'
* @return bool the length of the written string, or FALSE on failure
*/
function myfputcsv( $fp, $fields, $delimiter = ',', $enclosure = '"' )
{
/**
* Validate incoming values
*
* Weird corner cases are checked for here, so we can mimic fputcsv() as closely
* as possible. Eg we check whether or not an object passed as $delimiter or
* $enclosure implements __toString
*/
if ( !is_resource( $fp ) )
{
trigger_error( __FUNCTION__ . '() expects parameter 1 to be resource, ' . gettype( $fp ) . ' given', E_USER_WARNING );
return false;
}
if ( !is_array( $fields ) )
{
trigger_error( __FUNCTION__ . '() expects parameter 2 to be array, ' . gettype( $fields ) . ' given', E_USER_WARNING );
return false;
}
if ( is_object( $delimiter ) && method_exists( $delimiter, '__toString' ) )
{
$delimiter = ( string ) $delimiter;
}
if ( is_object( $enclosure ) && method_exists( $enclosure, '__toString' ) )
{
$enclosure = ( string ) $enclosure;
}
if ( $delimiter == null )
{
trigger_error( __FUNCTION__ . '(): delimiter must be a character', E_USER_WARNING );
return false;
}
if ( $enclosure == null )
{
trigger_error( __FUNCTION__ . '(): enclosure must be a character', E_USER_WARNING );
return false;
}
if ( !is_scalar( $delimiter ) )
{
trigger_error( __FUNCTION__ . '() expects parameter 3 to be string, ' . gettype( $delimiter ) . ' given', E_USER_WARNING );
return false;
}
if ( !is_scalar( $enclosure ) )
{
trigger_error( __FUNCTION__ . '() expects parameter 4 to be string, ' . gettype( $enclosure ) . ' given', E_USER_WARNING );
return false;
}
if ( strlen( $delimiter ) > 1 )
{
trigger_error( __FUNCTION__ . '(): delimiter must be a single character', E_USER_NOTICE );
$delimiter = $delimiter[0];
}
if ( strlen( $enclosure ) > 1 )
{
trigger_error( __FUNCTION__ . '(): enclosure must be a single character', E_USER_NOTICE );
$enclosure = $enclosure[0];
}
/**
* Prepare fields for writing to file by escaping them and wrapping them
* in $enclosure
*/
for( $i = 0; $i < sizeof( $fields ); $i++ )
{
/**
* Make a decision on whether or not to use $enclosure
*/
$use_enclosure = false;
if ( strpos( $fields[$i], $delimiter ) !== false )
{
$use_enclosure = true;
}
if ( strpos( $fields[$i], $enclosure ) !== false )
{
$use_enclosure = true;
}
if ( strpos( $fields[$i], "\" ) !== false )
{
$use_enclosure = true;
}
if ( strpos( $fields[$i], "\n" ) !== false )
{
$use_enclosure = true;
}
if ( strpos( $fields[$i], "\r" ) !== false )
{
$use_enclosure = true;
}
if ( strpos( $fields[$i], "\t" ) !== false )
{
$use_enclosure = true;
}
if ( strpos( $fields[$i], " " ) !== false )
{
$use_enclosure = true;
}
if ( $use_enclosure == true )
{
$fields[$i] = explode( "\$enclosure", $fields[$i] );
for( $j = 0; $j < sizeof( $fields[$i] ); $j++ )
{
$fields[$i][$j] = explode( $enclosure, $fields[$i][$j] );
$fields[$i][$j] = implode( "{$enclosure}{$enclosure}", $fields[$i][$j] );
}
$fields[$i] = implode( "\$enclosure", $fields[$i] );
$fields[$i] = "{$enclosure}{$fields[$i]}{$enclosure}";
}
}
/**
* Write fields as a $delimiter-delimited string, and return number of
* bytes written
*/
return fwrite( $fp, implode( $delimiter, $fields ) . "\n" );
}