PHP - 按列排列的CSV数组

时间:2014-09-24 23:30:40

标签: php arrays csv fputcsv

问题:我有一个关联数组,其中所有键代表csv标头,每个$ key中的值=> array ..表示该列中的项目。

研究>据我所知, fputcsv 喜欢逐行进行,但这个基于列的数组正在变得那么复杂。我没有找到任何完成此功能的功能。

示例:

Array(
    ['fruits'] => Array(
        [0] => 'apples',
        [1] => 'oranges',
        [2] => 'bananas'
    ),
    ['meats'] => Array(
        [0] => 'porkchop',
        [1] => 'chicken',
        [2] => 'salami',
        [3] => 'rabbit'
    ),
)

需要成为:

fruits,meats
apples,porkchop
oranges,chicken
bananas,salami
,rabbit

为什么这很难:

您需要知道制作空白点的最大行数。

2 个答案:

答案 0 :(得分:3)

我必须写自己的功能。想想也许它可能会帮助别人!

/*
 * The array is associative, where the keys are headers
 * and the values are the items in that column.
 * 
 * Because the array is by column, this function is probably costly.
 * Consider a different layout for your array and use a better function.
 * 
 * @param $array array The array to convert to csv.
 * @param $file string of the path to write the file.
 * @param $delimeter string a character to act as glue.
 * @param $enclosure string a character to wrap around text that contains the delimeter
 * @param $escape string a character to escape the enclosure character.
 * @return mixed int|boolean result of file_put_contents.
 */

function array_to_csv($array, $file, $delimeter = ',', $enclosure = '"', $escape = '\\'){
    $max_rows = get_max_array_values($array);
    $row_array = array();
    $content = '';
    foreach ($array as $header => $values) {
    $row_array[0][] = $header;
    $count = count($values);
    for ($c = 1; $c <= $count; $c++){
        $value = $values[$c - 1];
        $value = preg_replace('#"#', $escape.'"', $value);
        $put_value = (preg_match("#$delimeter#", $value)) ? $enclosure.$value.$enclosure : $value;
        $row_array[$c][] = $put_value;
    }
    // catch extra rows that need to be blank
    for (; $c <= $max_rows; $c++) {
        $row_array[$c][] = '';
    }
    }
    foreach ($row_array as $cur_row) {
    $content .= implode($delimeter,$cur_row)."\n";
    }
    return file_put_contents($file, $content);
}

而且:

/*
 * Get maximum number of values in the entire array.
 */
function get_max_array_values($array){
    $max_rows = 0;
    foreach ($array as $cur_array) {
    $cur_count = count($cur_array);
    $max_rows = ($max_rows < $cur_count) ? $cur_count : $max_rows;
    }
    return $max_rows;
}

新方式(使用课程)

我之后写了一个课程,我现在会为现在正在寻找的人提供一个课程:

class CSVService {

    protected $csvSyntax;

    public function __construct()
    {
        return $this;
    }

    public function renderCSV($contents, $filename = 'data.csv')
    {
        header('Content-type: text/csv');
        header('Content-Disposition: attachment; filename="' . $filename . '"');

        echo $contents;
    }

    public function CSVtoArray($filename = '', $delimiter = ',') {
        if (!file_exists($filename) || !is_readable($filename)) {
            return false;
        }

        $headers = null;
        $data = array();
        if (($handle = fopen($filename, 'r')) !== false) {
            while (($row = fgetcsv($handle, 0, $delimiter, '"')) !== false) {
                if (!$headers) {
                    $headers = $row;
                    array_walk($headers, 'trim');
                    $headers = array_unique($headers);
                } else {
                    for ($i = 0, $j = count($headers); $i < $j;  ++$i) {
                        $row[$i] = trim($row[$i]);
                        if (empty($row[$i]) && !isset($data[trim($headers[$i])])) {
                            $data[trim($headers[$i])] = array();
                        } else if (empty($row[$i])) {
                            continue;
                        } else {
                            $data[trim($headers[$i])][] = stripcslashes($row[$i]);
                        }
                    }
                }
            }
            fclose($handle);
        }
        return $data;
    }

    protected function getMaxArrayValues($array)
    {
        return array_reduce($array, function($carry, $item){
            return ($carry > $c = count($item)) ? $carry : $c;
        }, 0);
    }

    private function getCSVHeaders($array)
    {
        return array_reduce(
                array_keys($array),
                function($carry, $item) {
                    return $carry . $this->prepareCSVValue($item) . $this->csvSyntax->delimiter;
                }, '') . "\n";
    }

    private function prepareCSVValue($value, $delimiter = ',', $enclosure = '"', $escape = '\\')
    {
        $valueEscaped = preg_replace('#"#', $escape . '"', $value);
        return (preg_match("#$delimiter#", $valueEscaped)) ?
                $enclosure . $valueEscaped . $enclosure : $valueEscaped;
    }

    private function setUpCSVSyntax($delimiter, $enclosure, $escape)
    {
        $this->csvSyntax = (object) [
            'delimiter' => $delimiter,
            'enclosure' => $enclosure,
            'escape'    => $escape,
        ];
    }

    private function getCSVRows($array)
    {
        $n = $this->getMaxArrayValues($array);
        $even = array_values(
            array_map(function($columnArray) use ($n) {
                for ($i = count($columnArray); $i <= $n; $i++) {
                    $columnArray[] = '';
                }
                return $columnArray;
            }, $array)
        );

        $rowString = '';

        for ($row = 0; $row < $n; $row++) {
            for ($col = 0; $col < count($even); $col++) {
                $value = $even[$col][$row];
                $rowString .=
                        $this->prepareCSVValue($value) .
                        $this->csvSyntax->delimiter;
            }
            $rowString .= "\n";
        }

        return $rowString;
    }

    public function arrayToCSV($array, $delimiter = ',', $enclosure = '"', $escape = '\\', $headers = true) {
        $this->setUpCSVSyntax($delimiter, $enclosure, $escape);

        $headersString = ($headers) ? $this->getCSVHeaders($array) : '';

        $rowsString = $this->getCSVRows($array);


        return $headersString . $rowsString;
    }

}

答案 1 :(得分:0)

$data = array(
    'fruits' => array(
        'apples',
        'oranges',
        'bananas'
    ),
    'meats' => array(
        'porkchop',
        'chicken',
        'salami',
        'rabbit'
    ),
);

$combined = array(array('fruits', 'meats'));

for($i = 0; $i < max(count($data['fruits']), count($data['meats'])); $i++)
{   
    $row = array(); 

    $row[] = isset($data['fruits'][$i]) ? $data['fruits'][$i] : '';
    $row[] = isset($data['meats'][$i])  ? $data['meats'][$i]  : '';

    $combined[] = $row;
}

ob_start();

$fp = fopen('php://output', 'w');

foreach($combined as $row)
  fputcsv($fp, $row);

fclose($fp);

$data = ob_get_clean();

var_dump($data);

转换为csv并解析数组可以在同一个循环中完成。或者你的意思是可能有更多的列?对于一般类型的数组,可以轻松修改此代码。像这样,任意数量的列

$data = array(
    'fruits' => array(
        'apples',
        'oranges',
        'bananas'
    ),
    'meats' => array(
        'porkchop',
        'chicken',
        'salami',
        'rabbit'
    ),
);
$heads = array_keys($data);
$maxs = array();
foreach($heads as $head)
  $maxs[] = count($data[$head]);
ob_start();
$fp = fopen('php://output', 'w');
fputcsv($fp, $heads);
for($i = 0; $i < max($maxs); $i++)
{   
    $row = array(); 
    foreach($heads as $head)
       $row[] = isset($data[$head][$i]) ? $data[$head][$i] : '';
    fputcsv($fp, $row);   
}
fclose($fp);
$data = ob_get_clean();
var_dump($data);