

csvファイルに記載されているデータを画面に表示し、  
それをcsvとして出力するという課題に取り組んでいます。

文字化けを回避するよう記述しているつもりが、なかなかうまくいかず  
文字化けしてしまいます。

どなたか教えてください。

【元のcsvファイル】※仮のデータ  
"tanaka",5000  
"yoshida",1000  
"suzuki",400

【ブラウザに表示したいデータ】  
社員数：  
売上合計：  
平均売上：

上記をブラウザに表示しcsvファイルとしてダウンロードしたいという感じです。  
サンプルコードは下記に記載致します。

[code]

    <?php
    $datafile = 'sales.csv'; // CSV ファイル
    
    $fh = fopen($datafile, 'r');
    if ($fh) {
      flock($fh, LOCK_SH);
    
      $lst = array();
      while ($line = fgets($fh)) { // ファイルから一行ずつ読み込む
        $all = explode(',', chop($line)); // カンマで分割して配列に
    
        while (($key = array_shift($all)) && ($val = array_shift($all))) { // 配列の先頭から名前と値を取り出す
          $lst{$key} = $val; // 連想配列にセット
          $lst{$key} = mb_convert_encoding($lst{$key}, "SJIS", 'utf-8');
        }
      }
    
    $sum = 0;
    $count = 0;
    
    foreach ($lst as $name => $sale) {
      $count += 1;
      $sum += $sale;
      $avr = $sum / $count;
    }
    
    $fileName = "report.csv";
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=' . $fileName);
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . filesize($fileName));
    readfile($fileName);
    
    
    echo "社員数：".$count."<br>";
    echo "売上合計：".$sum."<br>";
    echo "売上平均：".$avr."<br>";
    
    flock($fh, LOCK_UN);
    fclose($fh);
    
    }
    ?>
    
[/code]

[![csv文字化け](https://i.stack.imgur.com/AHDhz.png)](https://i.stack.imgur.com/AHDhz.png)


CC BY-SA 3.0
2015-11-05T12:57:39.057
18438
2015-11-07T06:44:50.850
2015-11-07T04:00:07.323
7176
7176
question
php
PHPでcsvダウンロード際に文字化けする現象


mb_convert_encodingを使ってSJISにすると良いでしょうか。

以下に参考記事を紹介します。

[PHPでExcelで開いても文字化けしないCSVを出力する](http://qiita.com/ikemonn/items/f2bc4f9f834c989084ff)


CC BY-SA 3.0
2015-11-06T11:07:09.037
18477
2015-11-06T11:07:09.037
5778
18438
answer


CSVの期待する文字コードはSJISということでよろしいでしょうか？
元のCSVを読み込むときはwhile内でSJIS→UTF8への変換がされていると思うのですが、書き出す時に変換されておらず、UTF8のまま出力されているように見えます。  
echoでの出力内容を、入力時と同じようにmb_convert_encodingでUTF8→SJISに変換してやれば解決しませんでしょうか。


CC BY-SA 3.0
2015-11-06T16:27:26.610
18491
2015-11-06T16:27:26.610
7229
18438
answer


スクリーンショットで文字化けしている冒頭部分は、UTF-8で書かれた「社員数」をSJISとして表示したものです。Windows版のExcelは
`*.csv` のファイルをSJISで読み込みますが、Mac版も同様なのでしょう。

前述の文字列を表示している個所は

[code]

    echo "社員数：".$count."<br>";
    
[/code]

ですが、ここでSJISに変換することなく出力しているため、文字化けが起きています。

> report.csvとしてダウンロードしたい内容はブラウザに表示させる社員数・売上合計・平均売上です。

質問に書かれたプログラムでは `report.csv` を生成することはなく、読み取り出力しているだけですよね。なので `No such file or
directory` という、指定されたファイルが見つからないというエラーが `readfile()` で起きています。

`report.csv` をサーバー側で生成してもいいですが、別に `readfile()` を使わずとも `echo`
などで出力すればそのままダウンロードさせることができます。例えば、変数に含まれるデータをSJISのCSVでダウンロードさせるサンプルとして、以下のサイトなどはどうでしょうか。

[PHP で CSV ファイルをダウンロードさせる | モノリオ](http://monolio.com/memo/php/php-download-
csv/)

ちなみに現在のソースコードでも `mb_convert_encoding()` が使われていますね。

[code]

    $lst{$key} = mb_convert_encoding($lst{$key}, "SJIS", 'utf-8');
    
[/code]

この書き方でUTF-8からSJISへの変換を行いますが、この `$lst{$key}`
の中身は売上の数値列になります。半角英数はUTF-8でもSJISでも同じ表現になりますから、ここを変換する意味はないでしょう。

## 表示とダウンロード

ダウンロードする場合でもブラウザ上で表示する場合でも、サーバー側から送るデータは似たようなものです。 `Content-Disposition:
attachment;` というHTTPヘッダを付けることで、ブラウザがファイルのダウンロードとして扱うようになるのです。

HTTPヘッダはレスポンスの先頭に一度だけ設定するものなので、一回のレスポンスで「表示」と「ダウンロード」を同時にさせることはできません。今回の場合、
`header()` の前に `echo` した分までCSVに含まれてしまっていますね。

> ブラウザに表示させる処理とダウンロード処理を分けたほうがいいということでしょうか？（例：ボタンを押すとcsvとしてダウンロードされる）

ということになります。


CC BY-SA 3.0
2015-11-07T06:44:50.850
18508
2015-11-07T06:44:50.850
8000
18438
answer