<?php
/**
* Utility class for creating CSV-Formated output.
*/
class CSV {
var $urlEncode;
var $separator;
var $mime;
var $trim;
/**
* @param $urlEncode if true, URL-encode all values, so lines can be split
* reliably at the separator. If false, use CSV quotes.
* Defaults to true.
* @param $separator the field separator, defaults to ',' (comma)
*/
function CSV( $urlEncode = true, $separator = ',', $mime = NULL ) {
$this->urlEncode = $urlEncode;
$this->separator = $separator;
$this->trim = true;
if ($mime) $this->mime= $mime;
else {
#NOTE: url-encoding applies, so the charset is always us-ascii
#NOTE: text/csv is the correct mime type, but text/plain does not force
# download / external app in web browsers, so it's more convenient.
#$this->mime = "text/csv; charset=us-ascii; header=present; escape=url;";
$this->mime = "text/plain; charset=us-ascii;";
}
}
/**
* creates a CSV formatted line from the given values, without
* the trailing linebreak.
*
* @param $values the values to use
* @param $fields restrict values to the keys in this array. If NULL (default),
* all values will be used.
*/
function csvLine( $values, $fields = NULL ) {
if ( $fields ) {
#build a new value array,
#using only the keys from $fields
$v = array();
foreach ( $fields as $f ) {
$v[$f] = $values[$f];
}
$values = $v;
}
#escape quotes and separators
foreach ( $values as $i => $f ) {
if ( $this->trim ) {
$f = trim($f);
}
if ( $this->urlEncode ) {
$values[$i] = urlencode($f);
} else if ( strpos( $f, '"' ) !== false
|| strpos( $f, "\r" ) !== false
|| strpos( $f, "\n" ) !== false
|| strpos( $f, $this->separator ) !== false ) {
$values[$i] = '"' . str_replace('"', '""', $f) . '"';
}
}
return implode( $this->separator, $values );
}
/**
* Creates a page containing a CSV formatted table from
* a DB result set. Note that the caller is responsible
* for calling $dbr->freeResult( $res ) after this
* function.
*
* This function will set the Content-Type header to an
* appropriate value, and disable HTML output by calling
* $wgOut->disable();
*
* @param $dbr a database object
* @param $res the result set
* @param $fields columns to use. If null, all columns will be used.
* @param $mogrify an expression to evaluate to mogrify each line (array) before
* output. NULL per default. Inside the expression, the current
* row is available as $row.
*/
function csvFromDB( &$dbr, &$res, $fields = NULL, $mogrify = NULL ) {
header( "Content-Type: " . $this->mime );
$first = true;
while( true ) {
#if no fields are defined, look at the first record to
#find all column names.
if ( !$fields ) {
$obj = $dbr->fetchObject( $res );
if ( !$obj ) break;
$row = get_object_vars( $obj );
if ( $mogrify && $row) {
$row= eval( $mogrify );
}
$fields = array_keys( $row );
} else {
$row = $dbr->fetchRow( $res );
if ( $mogrify && $row) {
$row= eval( $mogrify );
}
}
# write header before first row.
# do inside loop becuase fields may not be known earlier
if ($first) {
$first= false;
$line = $this->csvLine( $fields, NULL );
print $line;
print "\r\n";
}
if ( !$row ) break;
$line = $this->csvLine( $row, $fields );
print $line;
print "\r\n";
}
#no more output
global $wgOut;
if (!is_null($wgOut)) $wgOut->disable();
}
/**
* Creates a page containing a CSV formatted table from
* an array. Each value in the array must be an object or an array.
*
* This function will set the Content-Type header to an
* appropriate value, and disable HTML output by calling
* $wgOut->disable();
*
* @param $data an array of objects or arrays. All rows should have the same fields.
* @param $fields columns to use. If null, all columns defined for the first record will be used.
* @param $mogrify an expression to evaluate to mogrify each line (array) before
* output. NULL per default. Inside the expression, the current
* row is available as $row.
*/
function csvFromArray( &$data, $fields = NULL, $mogrify = NULL ) {
header( "Content-Type: " . $this->mime );
$first = true;
foreach ( $data as $row ) {
if ( is_object( $row ) ) $row = get_object_vars( $row );
if ( $mogrify ) {
$row= eval( $mogrify );
}
#if no fields are defined, look at the first record to
#find all column names.
if ( !$fields ) {
$fields = array_keys( $row );
}
# write header before first row.
# do inside loop becuase fields may not be known earlier
if ($first) {
$first= false;
$line = $this->csvLine( $fields, NULL );
print $line;
print "\r\n";
}
$line = $this->csvLine( $row, $fields );
print $line;
print "\r\n";
}
#no more output
global $wgOut;
$wgOut->disable();
}
/**
* Creates a page containing a CSV formatted two-column table
* from an associative array (aka map).
*
* This function will set the Content-Type header to an
* appropriate value, and disable HTML output by calling
* $wgOut->disable();
*
* @param $map an associative array, assigning values to keys.
* @param $keycol the name of the column that is to contain the key of each entry.
* Default is 'key'.
* @param $valuecol the name of the column that is to contain the value of each entry.
* Default is 'value'.
* @param $mogrify an expression to evaluate to mogrify each line (array) before
* output. NULL per default. Inside the expression, the current
* row is available as $row.
*/
function csvFromMap( &$map, $keycol='key', $valucol='value', $mogrify = NULL ) {
$data= array();
foreach ($map as $k => $v) {
$data[]= array( $keycol => $k, $valucol => $v );
}
$this->csvFromArray( $data, $mogrify );
}
}
?>CSV.php
application/x-php, 6322 bytes (load raw)

