[PHP]str_getcsv()があるんならstr_putcsv()があってもいいじゃない

Read More

CSV文字列の取り込みに使えるstr_getcsv()。
str_getcsv()があるんならstr_putcsv()があってもいいじゃない!
って思った。


作った。


■CSV用の配列を取り込みCSV用の文字列を返す関数
<?php
/**
 * 2次元配列を取り込みCSV用の文字列を返す
 * ****************************************40
 * 注意:UTF-8の配列取り込みでUTF-8での出力となる
 * @param array $csv=null
 * @return string
 */
function str_putcsv($csv=null) {
  $buf=null;
  if(is_array($csv)) {
    $fp = fopen('php://memory', 'rw+');
    foreach($csv as $fields) fputcsv($fp, $fields);
    rewind($fp);
    $buf = stream_get_contents($fp);
    fclose($fp);
  }// end if
  return $buf;
}// end function
?>




これ作ったあとに同じ名前の関数が既にPHPで定義されてたらマズイなーと思ってちょとググった。

したらPHPでは定義されてなかったけど、ほぼ同じコードのものが既に書かれていることを知った。

愕然とした…


以前ググったときはそんなのHITしなかったのに。


もしかしてその時はstr_setcsv()でググったのかな?



はーあ…俺の1時間を返せ






--
ついでなのでCSVファイル取り込みの部分も載せておく。


以下はCSVファイルがアップロードされたのを想定してもの。



■CSVファイルの取り込みの流れ
<?php

// ファイルアップロードされた部分は省略
// えーと$_FILES['name']['tmp']だっけ?
// とにかく$file_pathにはCSVファイルまでのパスが入る


if($chk) $chk = file_exists($file_path);
if($chk) $chk = $fp = @fopen($file_path, 'r');
if($chk) $chk = @flock($fp, LOCK_SH);
if($chk) {
  $dat=null;
  while(!feof($fp)) {
  if($buf=fgets($fp, 1000))  $dat[]= $buf;
  }// end while
  $chk = (is_array($dat));
}// end if
if($chk) $chk = fclose($fp);
if($chk) $chk = checkEncoding($dat, 'SJIS-win');
if($chk) {
  $dat = my_convert_encoding($dat, 'UTF-8', 'SJIS-win');
  $csv=null;
  foreach($dat as $key => $val) {
    $csv[$key] = str_getcsv($val);
  }// end foreach
  $chk = (is_array($csv) and count($csv));
}// end if
if(!$chk) die('error');

print_r($csv);
?>



fopen()とflock()の@(アットマーク)演算子はたぶんいる。
動作が若干重くなるけどないとダメ。


えーとあとは…
checkEncoding()とmy_convert_encoding()って自作関数を使ってる。



checkEncoding()は試験的なやつだけど一応のせとこ。
<?php
/**
 * 文字エンコードのチェック
 * ****************************************40
 * 再帰呼び出し
 *
 * @param variant $var
 * @return boolean
 */
function checkEncoding($var=null, $encoding=null) {
  $chk=true;

  if(is_array($var)) {
    $f = __FUNCTION__;
    $c = __CLASS__;
    foreach($var as $key => $val) {
      if($chk) {
        if(isset($c) and $c) {
          $chk = $c::$f($val, $encoding);
        }else {
          $chk = $f($val, $encoding);
        }// end if
      }// end if
    }// end foreach
  }else {
    $chk = mb_check_encoding($var, $encoding);
  }// end if

  return $chk;
}// end function
?>




my_convert_encoding()はdolemのサイトに書いてあるけどまあこっちも一応のせとこ。
<?php
/**
 * 文字エンコードの変更
 * ****************************************40
 * 再帰呼び出し
 * 
 * @param variant $var=null
 * @param string $toEncType
 * @param string $frmEncType
 * @return variant
 */
function my_convert_encoding($var=null, $toEncType, $frmEncType) {
  if(is_array($var)) {
    foreach($var as $key => $value) {
      $var[$key] = null;
      $var[$key] = my_convert_encoding($value, $toEncType, $frmEncType);
    }// end foreach
  }else {
    $var = mb_convert_encoding($var, $toEncType, $frmEncType);
  }// end if

  return $var;
}// end function
?>





んでもって今度はCSVファイル出力のサンプル。
<?php
// $csvはarray(0=>array('a', 'i'), 1=>array('u','e'))みたいな配列?だっけ?

$temp_file_path = sys_get_temp_dir().'/csv_'.uniqid(mt_rand()).'.csv';
$fp = fopen($temp_file_path, 'w');
$buf = my_convert_encoding(str_putcsv($csv), 'SJIS-win', 'UTF-8');
fwrite($fp, $buf);
fclose($fp);

print $temp_file_path;
?>



ここで作成しているファイルは一時ファイルなので利用したらすぐunlink()するのがいいかも。
今回ちょっとsys_get_temp_dir()が使ってみたかったのでそのメモを兼ねてって感じ。

ちなみにこっちのfopen()はファイルがかぶることがないので@演算子はいらない。
flock()も同様の理由でいらん。



header()でCSVファイルのダウンロードの出力をする場合は一時ファイルに保存するは必要ないなあ。





-- 2017/10/02 一部プログラムを修正。
閉じカッコがない部分があった。





・関連
[PHP]fputcsv()でCSVを出力する際に各フィールドにダブルクォートを付ける
http://xirasaya.com/?m=detail&hid=411