/app/views/helpers/csv.php
PHP | 334 lines | 202 code | 52 blank | 80 comment | 39 complexity | cc534a581030ad3588bee3654a0f3877 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause, LGPL-2.1
- <?php
- /**
- * CSV helper for cakePHP. Compatible with version 1.1.x.x and higher.
- *
- * PHP versions 4 and 5
- *
- * Licensed under The MIT License
- *
- * @copyright Adam Royle
- * @license http://www.opensource.org/licenses/mit-license.php The MIT License
- */
- class CsvHelper extends Helper {
- var $delimiter = ',';
- var $enclosure = '"';
- var $filename = null;
- var $line = array();
- var $buffer;
- /**
- * This option preserves leading zeros on numeric data when opened in Excel.
- * Use it ONLY when the csv file is going to be opened in Excel, as it uses
- * non-standard syntax, and will probably break in other systems.
- */
- var $preserveLeadingZerosInExcel = false;
- var $_tmpFile = false;
- function CsvHelper() {
- $this->clear();
- }
- /**
- * Adds a multi-dimensional array to the buffer.
- *
- * @param array $data Multi-dimensional array
- * @param boolean $addFieldNames Add a row of field names before adding data
- * @access public
- */
- function addGrid($data, $addFieldNames = true, $fieldList = null) {
- if (!$data) {
- return false;
- }
- if (@is_array(reset($row = reset($data)))) {
- // Array generated by cakePHP model
- // eg.
- // $data = array(array('Model' => array('field_name' => 'field value')), array('Model' => array('field_name' => 'field value')))
- $defaultModel = key($row);
- if ($this->filename === null) {
- $this->setFilename(Inflector::pluralize($defaultModel));
- }
- if ($fieldList) {
- $fields = array();
- foreach ($fieldList as $fieldName) {
- if (strpos($fieldName, '.')) {
- list($modelName, $fieldName) = explode('.', $fieldName);
- } else {
- $modelName = $defaultModel;
- }
- $fields[] = array(Inflector::humanize($modelName), $fieldName);
- }
- if ($addFieldNames){
- foreach ($fields as $field) {
- if ($field[0] != $defaultModel) {
- $this->addField($field[0].' '.Inflector::humanize($field[1]));
- } else {
- $this->addField(Inflector::humanize($field[1]));
- }
- }
- $this->endRow();
- }
- foreach ($data as $row) {
- foreach ($fields as $field) {
- @$this->addField($row[$field[0]][$field[1]]);
- }
- $this->endRow();
- }
- } else {
- if ($addFieldNames){
- foreach (reset($row) as $key => $value) {
- $this->addField(Inflector::humanize($key));
- }
- $this->endRow();
- }
- foreach ($data as $row) {
- $this->addRow($row[$defaultModel]);
- }
- }
- } else {
- // Regular 2-dimensional array (with or without keys).
- // eg.
- // $data = array(array('field_name' => 'field_value'), array('field_name' => 'field_value'))
- // or
- // $data = array(array('field value'), array('field value'))
- if ($fieldList) {
- if ($addFieldNames){
- foreach ($fieldList as $fieldName) {
- $this->addField(Inflector::humanize($fieldName));
- }
- $this->endRow();
- }
- foreach ($data as $row) {
- foreach ($fieldList as $fieldName) {
- @$this->addField($row[$fieldName]);
- }
- $this->endRow();
- }
- } else {
- if ($addFieldNames) {
- foreach (reset($data) as $key => $value) {
- $this->addField(Inflector::humanize($key));
- }
- $this->endRow();
- }
- foreach ($data as $row) {
- $this->addRow($row);
- }
- }
- }
- }
- /**
- * Adds a single field value to the buffer. You must call $csv->endRow() to commit fields to the buffer.
- *
- * @param string $value Field value
- * @access public
- */
- function addField($value) {
- $this->line[] = $value;
- }
- /**
- * Commits the row of fields that were added by addField()
- *
- * @access public
- */
- function endRow() {
- $this->addRow($this->line);
- $this->line = array();
- }
- /**
- * Adds a single row to the buffer.
- *
- * @param array $row Data to be added
- * @access public
- */
- function addRow($row) {
- $row = (Array) $row;
- if ($this->preserveLeadingZerosInExcel) {
- // convert the number to a string formula
- foreach ($row as $key => $value){
- if (strlen($value) > 1 && $value[0] == '0' && is_numeric($value)) {
- $row[$key] = '="'.$value.'"';
- }
- }
- }
- fputcsv($this->buffer, $row, $this->delimiter, $this->enclosure);
- }
- /**
- * Outputs headers
- *
- * @param string $filename Filename to save as
- * @access public
- */
- function renderHeaders($filename = null) {
- if (is_string($filename)) {
- $this->setFilename($filename);
- }
- if ($this->filename === null) {
- $this->filename = 'Data.csv';
- }
- if ($this->filename) {
- header("Content-disposition:attachment;filename=".$this->filename);
- }
- header("Content-type:application/vnd.ms-excel");
- }
- /**
- * Sets the output filename. Automatically appends .csv if necessary.
- *
- * @param string $filename Filename to save as
- * @access public
- */
- function setFilename($filename) {
- $this->filename = $filename;
- if (strtolower(substr($this->filename, -4)) != '.csv') {
- $this->filename .= '.csv';
- }
- }
- /**
- * Returns CSV string and clears internal buffer. Outputs headers() if necessary.
- *
- * @param mixed $outputHeaders Boolean to determine if should output headers, or a string to set the filename
- * @param string $to_encoding Encoding to use
- * @param string $from_encoding
- * @return string String CSV formatted string
- * @access public
- */
- function render($outputHeaders = true, $to_encoding = null, $from_encoding = "auto") {
- if ($outputHeaders) {
- if (is_string($outputHeaders)) {
- $this->setFilename($outputHeaders);
- }
- $this->renderHeaders();
- }
- if ($this->_tmpFile) {
- rewind($this->buffer);
- $output = '';
- while (!feof($this->buffer)) {
- $output .= fread($this->buffer, 8192);
- }
- fclose($this->buffer);
- } else {
- rewind($this->buffer);
- $output = stream_get_contents($this->buffer);
- }
- // get around excel bug (http://support.microsoft.com/kb/323626/)
- if (substr($output,0,2) == 'ID') {
- $pos = strpos($output, $this->delimiter);
- if ($pos === false) {
- $pos = strpos($output, "\n");
- }
- if ($pos !== false) {
- $output = $this->enclosure . substr($output, 0, $pos) . $this->enclosure . substr($output, $pos);
- }
- }
- if ($to_encoding) {
- $output = mb_convert_encoding($output, $to_encoding, $from_encoding);
- }
- $this->clear();
- return $this->output($output);
- }
- /**
- * Clears internal buffer. This is called automatically by CsvHelper::render()
- *
- * @access public
- */
- function clear() {
- $this->line = array();
- $this->buffer = @fopen('php://temp/maxmemory:'.(5*1024*1024), 'r+');
- if ($this->buffer === false) {
- $this->_tmpFile = true;
- $this->buffer = tmpfile();
- }
- }
- }
- /**
- * A PHP4 implementation of the equivalent PHP5 function
- *
- * See (http://www.php.net/manual/en/function.fputcsv.php) for details
- */
- if (!function_exists('fputcsv')) {
- function fputcsv(&$handle, $fields = array(), $delimiter = ',', $enclosure = '"') {
- $str = '';
- $escape_char = '\\';
- foreach ($fields as $value) {
- settype($value, 'string');
- if (strpos($value, $delimiter) !== false ||
- strpos($value, $enclosure) !== false ||
- strpos($value, "\n") !== false ||
- strpos($value, "\r") !== false ||
- strpos($value, "\t") !== false ||
- strpos($value, ' ') !== false) {
- $str2 = $enclosure;
- $escaped = 0;
- $len = strlen($value);
- for ($i=0;$i<$len;$i++) {
- if ($value[$i] == $escape_char) {
- $escaped = 1;
- } else if (!$escaped && $value[$i] == $enclosure) {
- $str2 .= $enclosure;
- } else {
- $escaped = 0;
- }
- $str2 .= $value[$i];
- }
- $str2 .= $enclosure;
- $str .= $str2.$delimiter;
- } else {
- $str .= $value.$delimiter;
- }
- }
- $str = substr($str,0,-1);
- $str .= "\n";
- return fwrite($handle, $str);
- }
- }
- ?>