PHP5でfgetcsvが正常に動作しない
Posted on 7月 19, 2006
Filed Under PHP |
CSVのインポート機能を持ったシステムをPHP4環境からPHP5環境へ移行したら、
なぜかCSVデータを正しく読み込んでくれない。っていうか一文字目が文字化け。
超悩んだあげくぐーぐるさんで検索しても以下のような記事しかみつからず。
[PHP-dev 1205] PHP5のfgetcsv()関数について
人力検索はてな - PHP4からPHP5へソースの移(長いので略)
3つ目の掲示板のyossyはあたくし自身なんですが・・・。
setlocaleとかいろいろ試してもしても結局読み込まれるCSVの文字コードは
ほとんどSJISなせいなためかなんだかうまくいきません。
ちなみに検証環境はほぼFedoraCore4のデフォルトです。
PHPは5.0.4だったような気がします。
で、結局回避策として正規表現でCSVをぶった切ることにしました。
3つめのリンク先の掲示板に正規表現でCSV読み込む関数を書いたんですが、
改行を含んだCSVファイルには対応していなかったので
改行にも対応した関数を作りました。
Excel形式(というかRFC4180)に準拠したデータなら大丈夫・・・かな?
既存のfgetcsvとほとんど同じような感覚で使えるはず。うん。
<?php
/**
* ファイルポインタから行を取得し、CSVフィールドを処理する
* @param resource handle
* @param int length
* @param string delimiter
* @param string enclosure
* @return ファイルの終端に達した場合を含み、エラー時にFALSEを返します。
*/
function fgetcsv_reg (&$handle, $length = null, $d = ',', $e = '"') {
$d = preg_quote($d);
$e = preg_quote($e);
$_line = "";
while ($eof != true) {
$_line .= (empty($length) ? fgets($handle) : fgets($handle, $length));
$itemcnt = preg_match_all('/'.$e.'/', $_line, $dummy);
if ($itemcnt % 2 == 0) $eof = true;
}
$_csv_line = preg_replace('/(?:\r\n|[\r\n])?$/', $d, trim($_line));
$_csv_pattern = '/('.$e.'[^'.$e.']*(?:'.$e.$e.'[^'.$e.']*)*'.$e.'|[^'.$d.']*)'.$d.'/';
preg_match_all($_csv_pattern, $_csv_line, $_csv_matches);
$_csv_data = $_csv_matches[1];
for($_csv_i=0;$_csv_i<count($_csv_data);$_csv_i++){
$_csv_data[$_csv_i]=preg_replace('/^'.$e.'(.*)'.$e.'$/s','$1',$_csv_data[$_csv_i]);
$_csv_data[$_csv_i]=str_replace($e.$e, $e, $_csv_data[$_csv_i]);
}
return empty($_line) ? false : $_csv_data;
}
?>
この関数を↓こんな感じで。
<?php
$row = 1;
$handle = fopen("test.csv", "r");
while (($data = fgetcsv_reg($handle)) !== false) {
$_enc_to=mb_internal_encoding();
$_enc_from=mb_detect_order();
mb_convert_variables($_enc_to,$_enc_from,$data);
$num = count($data);
echo "<p> $num fields in line $row: </p><br />n";
$row++;
for ($c=0; $c < $num; $c++) {
echo nl2br($data[$c]) . "<br />n";
}
}
fclose($handle);
?>
Comments
Leave a Comment
If you would like to make a comment, please fill out the form below.
Recently
- mixiアプリ「ビデオチャット」のオープンソース化
- [mixiアプリ] Flexでニックネームが一部文字化ける
- 【mixiアプリ】ビデオチャットmixiアプリをローンチ
- データベーススペシャリスト試験
- mixiアプリのお勉強
- MAGNIFICENT @ 新木場 ageHa 2008-04-12
- 入学式に行ってきました@品川シーサイド AIIT 2008-04-05
- 平成20年4月より学生さんになりますっ。
- アプリケーションエンジニア試験
- Open Source Conference 2007 .DB @ 蒲田 2007-06-23
Categories
- AIIT
- Apache
- COBOL
- Database
- Flex
- Hardware
- Linux
- MovableType
- MySQL
- OSS
- Others
- PG全般
- PHP
- Seasar
- Smarty
- Software
- symfony
- Web関連
- 技術書
- 雑記
- 音楽 > JPop
- 音楽 > Trance
Archives
- 2010年 1月
- 2009年 9月
- 2009年 7月
- 2009年 5月
- 2008年 4月
- 2007年 12月
- 2007年 6月
- 2007年 5月
- 2007年 4月
- 2007年 3月
- 2007年 1月
- 2006年 12月
- 2006年 11月
- 2006年 10月
- 2006年 9月
- 2006年 8月
- 2006年 7月
- 2006年 6月
- 2005年 12月
- 2005年 7月
- 2005年 5月
- 2005年 4月
- 2005年 3月
- 2005年 2月
- 2005年 1月
- 2004年 12月
ありがとうございます。
pukiwikiのトラックバックのバグ修正に使わせてもらいました。
すばらしいです。
おかげさまでシンプルに処理できるようになりました。ありがとうございます。
ありがとうーーーー
感謝します!
素晴らしいです。
一発で問題が解決しました。
ありがとうございます。
悩み解決しました。
ありがとうございます!!
感謝!!!
この関数、間違って「”」が奇数個あるファイルを読み込むと、whileループから抜けられなくなりませんか?
関数の5行目
$_line .= (empty($length) ? fgets($handle) : fgets($handle, $length))
を、こんなふうにすれば直るような気がします。
$s = (empty($length) ? fgets($handle) : fgets($handle, $length));
if (!$s) {break;}
fgetcsv_reg にはお世話になりました。ありがとうございます。
で、上のコメントの無限ループについて、
while ($eof != true) {
を
while (($eof != true)and(!feof($handle))) {
に書きかえればOKではないかと。
助かりました。ありがとうございます
素晴らしすぎます!ありがとうございます!
同じ問題で困っていたところでした。
ありがとうございます!
本当に助かりました。:-)
私もこれで困っていました。非常に助かりました。ありがとうございます。
netcommonsで応用させて頂きました。
1行用
function fgetcsv_reg($line, $length = null, $d = ‘,’, $e = ‘”‘) {
$d = preg_quote($d);
$e = preg_quote($e);
$itemcnt = preg_match_all(’/’.$e.’/', $line, $dummy);
$_csv_line = preg_replace(’/(?:\r\n|[\r\n])?$/’, $d, trim($line));
$_csv_pattern = ‘/(’.$e.’[^’.$e.’]*(?:’.$e.$e.’[^’.$e.’]*)*’.$e.’|[^’.$d.’]*)’.$d.’/';
preg_match_all($_csv_pattern, $_csv_line, $_csv_matches);
$_csv_data = $_csv_matches[1];
for($_csv_i=0;$_csv_i