Last active
August 29, 2015 13:57
-
-
Save amirkdv/9764785 to your computer and use it in GitHub Desktop.
simple CSV r/w utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// First pass at a small CSV r/w utility. Before hacking at this, consider https://packagist.org/search/?q=csv | |
/** | |
* extracts the list of fields of a given associative array, | |
* @param array[][] $data | |
* @return array[] | |
* @throws Exception | |
* if provided associative array is inconsistent | |
*/ | |
function fields($data){ | |
// extract field names from first item | |
if(empty($data)){ | |
return array(); | |
} | |
$sample=$data[0]; | |
$fields=array(); | |
foreach($sample as $key=>$value){ | |
$fields[] = $key; | |
} | |
// check consistency | |
foreach($data as $datum){ | |
// ensure datum does not have extra fields | |
foreach($datum as $key=>$value){ | |
if (!in_array($key,$fields)){ | |
$message = "the following item has an extra field '$key':\n" . print_r($datum,1); | |
throw new Exception($message); | |
} | |
} | |
// ensure datum is not missing fields | |
// array_key_exists returns TRUE if value is NULL, isset does not | |
foreach($fields as $field){ | |
if (!array_key_exists($field, $datum)){ | |
$message = "the following item does not have a field '$field':\n" . print_r($datum,1); | |
throw new Exception($message); | |
} | |
} | |
} | |
return $fields; | |
} | |
/** | |
* assembles CSV equivalent for given associative array | |
* @param array[][] $data | |
* @return string | |
* @throws Exception | |
* if provided associative array is inconsistent | |
*/ | |
function write_csv($data){ | |
$fields = fields($data); | |
// write data to string stream | |
$handle = fopen('data://text/plain;base64,','w'); | |
fputcsv($handle,$fields,',', '"'); | |
foreach($data as $datum){ | |
fputcsv($handle, $datum, ',', '"'); | |
} | |
// dump and close string stream | |
$output = stream_get_contents($handle,-1, 0); | |
fclose($handle); | |
return $output; | |
} | |
/** | |
* reads multiple lines of CSV data into associative arrays | |
* does not respect header/non-header | |
* | |
* @param string $string | |
* @return array[]|array[][] | |
*/ | |
function read_csv_rows($string){ | |
$data = array(); | |
$handle = fopen('data://text/plain;base64,','w'); | |
fwrite($handle, $string); | |
fseek($handle, 0); | |
while ( $item = fgetcsv($handle, 0, ',', '"', '\\') ){ | |
$data[] = $item; | |
} | |
fclose($handle); | |
return $data; | |
} | |
/** | |
* reads CSV string including a header into an associative array | |
* @param string $string | |
* @return array[][] | |
* @throws Exception | |
* if provided CSV string is inconsistent | |
*/ | |
function read_csv($string){ | |
list($header,$data) = explode("\n", $string, 2); | |
// extract field names from header | |
$header_export = read_csv_rows($header); | |
$fields = $header_export[0]; | |
// extract data from the rest | |
$data_export = read_csv_rows($data); | |
// assign labels to retrieved data: | |
$data = array(); | |
foreach($data_export as $item){ | |
$datum = array(); | |
foreach($item as $key => $value){ | |
if (!isset($fields[$key])){ | |
$message = "The following item has extra fields:\n" . print_r($item,1); | |
throw new Exception($message); | |
} | |
$datum[$fields[$key]]= $value; | |
} | |
$data[] = $datum; | |
} | |
// check whether assembled data is consitent | |
fields($data); | |
return $data; | |
} | |
/** | |
* dummy testing utility to be killed in favor of PHPUnit ASAP. | |
*/ | |
function test_case($json_data){ | |
try { | |
$data = json_decode($json_data,true); | |
$csv = write_csv($data); | |
print $csv; | |
$ext = read_csv($csv); | |
if (print_r($data,1) === print_r($ext,1)){ | |
print "success\n"; | |
} else { | |
print "failure, mismatch\n"; | |
} | |
} catch (Exception $e){ | |
print "failure, caught Exception:\n"; | |
print $e->getMessage(); | |
} | |
} | |
$test= 'good.json'; | |
print "running test $test, should succeed:\n"; | |
test_case(file_get_contents($test)); | |
print "---------\n"; | |
$test= 'missing_field.json'; | |
print "running test $test, should fail; missing field comment:\n"; | |
test_case(file_get_contents($test)); | |
print "---------\n"; | |
$test= 'extra_field.json'; | |
print "running test $test, should fail; extra field age:\n"; | |
test_case(file_get_contents($test)); | |
print "---------\n"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"id": 12, | |
"name": "Mary-Anne", | |
"comment": "Multiline\nis\nOK" | |
}, | |
{ | |
"id": "13", | |
"name": "John O'connor", | |
"comment": "Double Quotes like '\"' OK", | |
"age" : 42 | |
}, | |
{ | |
"id": 14, | |
"name": "", | |
"comment": null | |
} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"id": 12, | |
"name": "Mary-Anne", | |
"comment": "Multiline\nis\nOK" | |
}, | |
{ | |
"id": "13", | |
"name": "John O'connor", | |
"comment": "Double Quotes like '\"' OK" | |
}, | |
{ | |
"id": 14, | |
"name": "", | |
"comment": null | |
} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"id": 12, | |
"name": "Mary-Anne", | |
"comment": "Multiline\nis\nOK" | |
}, | |
{ | |
"id": "13", | |
"name": "John O'connor", | |
"comment": "Double Quotes like '\"' OK" | |
}, | |
{ | |
"id": 14, | |
"name": "" | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment