diff --git a/familyconnections/addressbook.php b/familyconnections/addressbook.php index daa87167..7cb0aa4c 100644 --- a/familyconnections/addressbook.php +++ b/familyconnections/addressbook.php @@ -192,11 +192,33 @@ function displayExportSubmit () return; } - $csv = "lname, fname, address, city, state, zip, email, home, work, cell\015\012"; + $csv = ''; + $handle = fopen('php://temp', 'w+'); + + if ($handle !== false) + { + fputcsv($handle, array('lname', 'fname', 'address', 'city', 'state', 'zip', 'email', 'home', 'work', 'cell')); + } foreach ($rows as $row) { - $csv .= '"'.join('","', str_replace('"', '""', $row))."\"\015\012"; + $safeRow = array(); + foreach ($row as $field) + { + $safeRow[] = cleanCsvField($field); + } + + if ($handle !== false) + { + fputcsv($handle, $safeRow); + } + } + + if ($handle !== false) + { + rewind($handle); + $csv = stream_get_contents($handle); + fclose($handle); } $date = fixDate('Y-m-d', $this->fcmsUser->tzOffset); diff --git a/familyconnections/inc/utils.php b/familyconnections/inc/utils.php index 73400965..9b705af7 100644 --- a/familyconnections/inc/utils.php +++ b/familyconnections/inc/utils.php @@ -1223,6 +1223,28 @@ function cleanFilename ($filename) return $filename; } + +/** + * cleanCsvField + * + * Prevents spreadsheet formula execution when exporting user-controlled CSV. + * + * @param string $field + * + * @return string + */ +function cleanCsvField ($field) +{ + $field = (string)$field; + + if (preg_match('/^\s*[=+\-@]/', $field)) + { + return "'".$field; + } + + return $field; +} + /** * unhtmlentities *