循环遍历数组以CSV格式提供所有数据

时间:2017-11-23 23:46:51

标签: php codeigniter loops

所以我有这段代码:

$list = $this->user_model->get_users($prefKey, $searchKey, $withEmail, "", "");

$headerArray = array("id", "prefecture_id", "industry");

$header = str_replace(",", "", $headerArray);

$datas = implode(',', $header) . "\r\n";

foreach($list as $body)
{
    $orig_email = $body['email'];

    $mstring = preg_replace("/^([^a-zA-Z0-9])*/",',',$orig_email);

    preg_match_all("/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i", $mstring, $matches);

    $email = implode($matches[0]);

    $datas .= $body["id"].",".$body["prefecture_id"].",".$body["industry_id"].",".$email."\r\n";

    $datas = '"' . implode('","', $body).'"';

}

$datas = mb_convert_encoding($datas, "SJIS-win", "UTF-8");

$csvFileName = "phpList_" . date('Ymd_His') . ".csv";


header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $csvFileName);
header('Content-Transfer-Encoding: binary');
while (ob_get_level() > 0)
{
    ob_end_clean();
}

ob_start();
print trim($datas);
ob_flush();
ob_end_clean();
exit;

它只是这样:

"3","Tesla","Cars","admin@volvo.com"

我想要的是这样的:

"1","Volvo","Cars","admin@volvo.com"
"2","Honda","Cars","admin@honda.com"
"3","Tesla","Cars","admin@tesla.com"

当我调用此函数时,它只给出csv下载文件,只有1个数据(最终数据)。如何遍历所有数据?

2 个答案:

答案 0 :(得分:3)

你是说你只获得了csv中加载的最后一条记录吗?

使用此行替换当前$datas中的所有数据:

$datas = '"' . implode('","', $body).'"';

这样,只有循环的最后一次迭代的最后一行最终对最终结果有用。不确定这是不是问题,但也许

$datas .= '"' . implode('","', $body).'"';

P.S。我不确定您是否要保留foreach

的第一行

P.p.s。您可能希望在csv中添加一些行结尾。

答案 1 :(得分:2)

您的变量被覆盖

foreach($list as $body){
  ....
    $datas .= $body["id"].",".$body["prefecture_id"].",".$body["industry_id"].",".$email."\r\n";

    $datas = '"' . implode('","', $body).'"';  //overwritten by body
}

这两条线对它们的方式毫无意义。每次迭代你+ =连接$datas,然后你立即用其他数据覆盖它。

例如,在第一次迭代时它是

$datas = implode(',', $header) . "\r\n";
$datas .= $body["id"].",".$body["prefecture_id"].",".$body["industry_id"].",".$email."\r\n";
$datas = '"' . implode('","', $body).'"'; //over written

下一次迭代是前一次(上面的最后一行)

$datas = '"' . implode('","', $body).'"';

然后

  $datas .= $body["id"].",".$body["prefecture_id"].",".$body["industry_id"].",".$email."\r\n";
  $datas = '"' . implode('","', $body).'"';  //over written

看看我的意思是没有意义的。

使这有意义的唯一方法是做这样的事情

$datas = [implode(',', $header)];

foreach($list as $body)
{
    $orig_email = $body['email'];

    $mstring = preg_replace("/^([^a-zA-Z0-9])*/",',',$orig_email);
    preg_match_all("/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i", $mstring, $matches);

    $email = implode($matches[0]);

    $datas[] = [
         $body["id"],
         $body["prefecture_id"],
         $body["industry_id"],
         $email
    ];

}

$datas = imploade(PHP_EOL, $datas);

但即使这不是制作csv文件的正确方法,您应该使用fputcsv。如果"中的$body您的CSV将被废弃,会发生什么。

更新和解决方案

这就是我编码的方式,但我不知道你为什么要更改编码:

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $csvFileName);
header('Content-Transfer-Encoding: binary');

//open the output stream, this acts like a file but just outputs the contents.
$f = fopen('php://output', 'w');

fputcsv($f, $header);

//create a mapping array for the headers ( if the order is different then $body )
$default = array_fill_keys( $headers, '');
/*
 assuming headers is like this
     ['id', 'prefecture_id', 'industry_id', 'email']
 this will create a "mapping" array like this
     ['id'=>'', 'prefecture_id'=>'', 'industry_id'=>'', 'email'=>'']
*/

foreach($list as $body)
{
    $orig_email = $body['email'];

    $mstring = preg_replace("/^([^a-zA-Z0-9])*/",',',$orig_email);

    if( preg_match_all("/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i", $mstring, $matches)){  
         $body['email'] = implode($matches[0]);
    }else{
         //prevent undefined offset warning in $matches when there are none.
         $body['email'] = '';
    }

    /*
       merge $body with the mapping array
       if the keys match the '' in $default will be replaced by the 
       value in $body for the same key.
     ----------------------------------------
       assuming data like this '$body'
      ['email' => 'mail@example.com', 'industry_id'=>321,'id'=>1, 'prefecture_id' => 123]
       and our mapping like this '$default'
      ['id'=>'', 'prefecture_id'=>'', 'industry_id'=>'', 'email'=>'']
      this will change $body to
      ['id'=>1, 'prefecture_id'=>123, 'industry_id'=>321, 'email'=>'mail@example.com']
    */
    $body = array_replace($default, $body);

    //after mapping it $body will match $header order and lenght
    //so we just send it to the output stream buffer.
    fputcsv($f, $body);

    //flush the output buffer to the browser.
    flush();
}

供参考(关于如何将数据映射到标题)

  

array_fill_keys()使用keys数组的值作为键,使用value参数的值填充数组。

http://php.net/manual/en/function.array-fill-keys.php

  

array_replace()将array1的值替换为以下每个数组中具有相同键的值。如果第一个数组中的键存在于第二个数组中,则其值将替换为第二个数组中的值。

http://php.net/manual/en/function.array-replace.php