PHPから受け取ったデータをJavaScriptでCSV出力(UTF-8とSJISに対応)

いろいろなファイルアイコン(文字)
思ってたんと違った結果になったのでメモ。以前も似たような記事は書いたんですけど。



やりたいこと

  • AjaxでPHPにデータを投げる
  • PHPでデータを加工する
  • 加工されたデータをCSVとしてダウンロード出来させる
  • CSVはUTF-8とS-JISの出力に対応(ユーザーが選択出来る)
  • 動作環境に関する特記事項:全ブラウザ対応でなくて良い、jQuery使用






最終的にこんな感じになりました(抜粋)

データを受け取ったPHP側の処理



  1. 受け取ったデータをカンマ区切りで1行に繋げて改行コードを付加
  2. 各項目がダブルクオーテーションで囲まれていないとExcelで開けないことがあるので、値をエスケープしつつダブルクオーテーションで囲む
  3. JSON形式にエンコードして出力


Ajaxでのデータ送信および受信とCSV出力



  1. 返ってきたデータを指定したコードに合わせてエンコードする(encoding.jsを使用)
  2. データをBrobにセットする
  3. リンクを作成する
  4. 作成したリンクをクリックしてダウンロードさせる



ポイント

実はCSVをダウンロードするコードは以前も書いてました。


管理アプリケーションから任意のレコードを選択してボタンを押すと、用途に合わせた情報が抽出されてCSVファイルとしてダウンロード出来る……という要件を満たすために、最初はPHP主体で処理することを考えていたのですが、色々調べてみるとほとんどJavaScriptで出来ることがわかりました。あとで記載する参考リンクの情報を組み合わせるとこんな感じ。

JavaScriptでデータからCSVファイルを生成しダウンロードさせる – NOBODY:PLACE


ギミックのほとんどは今回書いたのと同じです。つまりAjaxとPHPでCSVダウンロードなんて本来簡単な処理なんですけど、「Windows上のExcelで開けるようにして欲しい」「Shift_Jisでエンコードして欲しい」という要件が加わると途端に面倒になるから困る。

Windows上のExcelで開くために必要なこと(リクエストベース)

  • 文字コードは「Shift_Jis」
  • 日本語はダブルクオーテーションで囲まなければならない
  • タブ区切りよりカンマ区切り推奨

UTF-8で出力したタブ区切りのデータをCSVファイルとしてダウンロードすれば済むところ、エンコードやら文字の処理やらいろいろ必要になります。

本来ならUTF-8で出力したCSVもExcelは開ける(ただしBOM付きのUTF-8にする必要がある)ので、Shift_Jisで出力する必要なんか無いんですけどそういうリクエストなので仕方ない。その後にどんな処理を行うかわからないし。それからタブ区切りだと上手くデータを分割してくれないことがあります。1つのセルに1行分のデータが全部入っちゃうの。なのでカンマ区切りするのが良いんですけどそうなると今度はカンマをエスケープするか、ダブルクオーテーションで囲むかの処理が必要になってきます。

しかも僕知らなかったんですけど、

PHPのjson_encode()にShift_Jisのデータを入れるとエラーになる


んですね。ほんとまったくしらなくて、なんでUTF-8だと動くのにShift_Jisだと動かないのかしばらく悩みました。JSONというのはそもそもunicodeをベースに設計されているのでエラーが出て当然、むしろエラーが出てくれることがありがたいわけですけど、当初PHP側でエンコードした上でJSON出力してたのでShift_Jisで出力出来なくなってかなり嵌まりました。

最終的にはエンコードはJavaScriptの仕事ということにして解決しましたが、そうなると当然CSV出力をJavaScript側に実装することになるわけで、難易度が上がるしブラウザごとの対応も必要になります。上のJavaScriptコードはIEでは動きませんし。ただ今回はバックヤード側の機能で使用環境がかなり予想出来る状態だったので良しとしました。


CSVダウンロードのギミックがこれでいいの感

もしかしたら上手く動かない環境があったり、データ長でエラーが出たりすることがあるのかも知れませんが、そんときはそんとき。そこまで重い使われ方するのであれば、むしろもうCSVファイルとして出力してS3にアップロードしてリンクを出力するとかメールするとかした方が良いので、現状はこれでOKとしました。



いやーなんか久しぶりなハマり方しました。知らないことたくさんあるなあ。