いろいろあったのだけど、ようするに使えないということがわかった……。忘れないように書いとく。
PHPにfgetcsv()という便利関数があって。ファイルをCSVとして一行とりだして、各列の値を配列に入れて返すというものなんだが。
PHP4のはじめのころは、バグだらけなので有名だったらしいのだけど、さすがにPHP5.2なら大丈夫だろうと思ったら。しかしダメ。
マルチバイト文字の2バイト目に'\'があると、直後のダブルクォーテーションをエスケープするという、少なくともEXCELの仕様にはない独自解釈をするらしく。つまりSJISのファイルを読ませるとうまくいかない。
(ただし、EXCELがCSVをどう解釈するかという仕様は公開されてなさげ)
じゃあEUCに変換してから読ませれば、いちおうは大丈夫なんだけど、もちろん機種依存文字が化ける。 ←(これは指摘されたのでいちおう修正。SJIS-winからEUCJP-winとかUTF-8とかに変換すれば使える。けどめどい)
だいだいCSVを使うときというのはEXCELからくるデータなわけで。文字コードはSJISだし、機種依存文字も使いまくりがあたりまえだ。それがいけないのではあるけど、しかし対応するしかないし。
もしどうしても使うなら、あらかじめ機種依存文字を安全な文字列に変換して、EUCにして保存し、そのあとでファイルを開いてfgetcsv()するとか?(やる気にならないから試してない)もちろん、そんなことするなら自分で処理を書いたほうがいい。 ←(これもSJIS-winとか指定すれば特別な変換はいらない)
というわけで。もう二度と使わないぞ。
というわけで、できるだけExcelの動きに近づけてみた関数を作ってみたんだ。
調べてみると、セル中でダブルクォートが出てきたときとか、あんたほんとにそれでいいのかと思う動きをするけど、あくまでそんなExcelを再現しようとしてみる。
function fgetExcelCSV(&$fp , $length = null , $delimiter = ',' , $enclosure = '"') { $line = fgets($fp); if($line === false) { return false; } $bytes = preg_split('//' , trim($line)); array_shift($bytes);array_pop($bytes); $cols = array(); $col = ''; $isInQuote = false; while($bytes) { $byte = array_shift($bytes); if($isInQuote) { if($byte == $enclosure) { if($bytes[0] == $enclosure) { $col .= $byte; array_shift($bytes); } else { $isInQuote = false; } } else { $col .= $byte; } } else { if($byte == $delimiter) { $cols[] = $col; $col = ''; } elseif($byte == $enclosure && $col == '') { $isInQuote = true; } else { $col .= $byte; } } while(!$bytes && $isInQuote) { $col .= "\n"; $line = fgets($fp); if($line === false) { $isInQuote = false; } else { $bytes = preg_split('//' , trim($line)); array_shift($bytes);array_pop($bytes); } } } $cols[] = $col; return $cols; }
つまりなにがいいたいかというと、
っていうかそんなの例外ケースなので、やる必要はまったくないけど(笑)
[2007.10.27 11:22]anonymous :
CSVファイルをSJIS-winからUTF-8に変換してから、
fgetcsv()を使用し、UTF-8からSJIS-winに戻せば
機種依存文字等も壊れないけどね。
※SJIS→EUCだと壊れる。
[2007.10.27 21:47]てらしま :
実際仕事ではそういうことやりましたが(笑) けっきょく、それでもExcelと動作が違っていると、いつか不具合といわれても不思議はないのが現実なんですよねえ。
[2007.10.28 01:12]てらしま :
というわけで、まあ指摘いただいたのでいちおう上の内容を修正しときます。
[2007.11.02 12:00]anonymous :
fgetExcelCSV()って、セル内に改行がある場合に対応してないのでは?
fgetcsv() はセル内に改行がある場合に対応してるけど…。
[2007.11.02 23:18]てらしま :
対応してるはずです。がやってみてうまくいかなかったら、なおすなりなおせというなりしてください。
うえき -2009/07/13 18:16
わかりやすいソースですね。このソース(fgetExcelCSV)のライセンスを教えてください。
サイトで使わせていただきたいと思っています。
てらしま -2009/07/13 19:16
……考えてもいなかったです。
なにをどうされてもかまわないです。とりあえずNYSL0.9982にしたがいます、ということでおねがいします。
うえき -2009/07/14 09:59
ありがとうございます。使わせていただきます。
Motty -2012/08/20 16:35
今だに fgetcsv に悩まされていました。
このページに救われました!
fgetExcelCSV使わせて頂きます。
有難うございます。
てらしま -2012/08/21 16:07
いやその、読んでいただいたのは嬉しいですが。
これはもう何年も前に書いたもので、しかも半分冗談の書き殴りコードです。使用はおすすめしません。
もっと新しくていいものがあるので、そちらを探してください。