[php]csvをアップロードして編集してダウンロードする

これ系は久しぶりにやる

環境

php7.4で動作することが前提。
動けば正義。

やりたいこと

ECサイトと出荷システムが連携しないので、csvを介して手作業で繋ぐ必要がある。お互いのインポートとエクスポートが柔軟なおかげで項目を紐付けられたのでcsv自体は読み込めるんだけど、出力する内容がそのままだと通用しない。

「銀行振込み」で書き出すけど「銀行振込」じゃないと登録できないとか、「クレジットカード」だけど「クレジットカード決済」じゃないとダメとか、そういう感じの。

Excelだと数値関係がアレだし、テキストエディタで開いたとしても置換の数が多いと面倒だし、そもそも手作業で中身を編集するのはリスクがある。

でも編集しないとどうしようもないから、じゃあphpで書き換えてしまえという結論に至る。

設計イメージ

やることは単純。

  1. WEBサーバー上にCSVをアップロード
  2. CSVを編集・置換
  3. 編集したCSVをダウンロード

ついでに、編集前と後で見分けがつくようにリネーム。

同一ディレクトリ内に以下の3つを用意するとする。

  • アップロード用のページ(input.php)
  • CSV編集・ダウンロード用のページ(generate.php)
  • CSVを保存するディレクトリ(./dir)

アップロードページ

これも簡単。

<form action="generate.php" method="post" enctype="multipart/form-data">
	<input type="file" name="uploadcsv">
	<button type="submit">GENERATE</button>
</form>

編集・DLファイル作成ページ

<?php
//ファイルアップロード
$tempfile = $_FILES['uploadcsv']['tmp_name']; // 一時ファイル名
$filename = './dir/' .$_FILES['uploadcsv']['name']; // 本来のファイル名
$outputname = './dir/output_' .$_FILES['uploadcsv']['name'];
// DLファイル名
if (is_uploaded_file($tempfile)) {
    if ( move_uploaded_file($tempfile , $filename )) {
	echo $filename . "をアップロードしました。";
    } else {
        echo "ファイルをアップロードできません。";
    }
} else {
    echo "ファイルが選択されていません。";
} 


// CSV読み込み
$input = file_get_contents($filename);
// Shift-JISからUTF-8へ変換
$input = mb_convert_encoding($input, 'UTF-8', 'SJIS-win');

// 一時ファイルにUTF-8エンコードされたCSVを書き込む
$tmp = tmpfile();
$meta = stream_get_meta_data($tmp);
fwrite($tmp, $input);

// 一時ファイルから読み込み
$csv = new SplFileObject($meta['uri']);
// CSVとしてファイルを読み込ませる
$csv->setFlags(SplFileObject::READ_CSV);

// 書き出し用のCSVファイル
$output = new SplFileObject($outputname, 'w');

foreach ($csv as $i => $row)
{
  // 空行でない場合
  if ($row[0])
  {
    // 1行目以降のセルを書き換える
    if ($i !== 0)
    {
		$row = str_replace('銀行振込み','銀行振込',$row);
    }
    
    // 行を書き出し
    $output->fputcsv($row);
  }
}

// CSV読み込み
$output = file_get_contents($outputname);
// UTF-8からShift-JISへ変換
$output = mb_convert_encoding($output, 'SJIS-win', 'UTF-8');
file_put_contents($outputname, $output);

// ファイル閉じる
$csv    = null;
$output = null;

?>
<a href="<?php echo $outputname; ?>">download</a>

PC上のファイルを直接どうのこうのはできないのでアップロードする必要があった。アップロードしたCSVを展開して、行単位で編集・DL用ファイルに書き出し。foreachで元データの行数だけ繰り返す。

「$row = str_replace(‘銀行振込み’,’銀行振込’,$row);」が編集部分。
他にもあれば足していく。
やりたいことが決まりきってるならPHP上に全部書けばいいし、柔軟な置換とかを仕込みたいなら手前のformで色々仕込んでもいい。

今回は書き出すまでがゴールなのでサーバーにはCSVファイルが溜まる仕組みになってる。DL用CSV生成に合わせて元CSVを削除するとか、DL用CSVをDLしたらそれも削除するとか、単純に保存用ディレクトリを空にするボタンを付けるとか、メンテナンスが楽かも。

アップロードファイルの有無を処理の手前に仕込んでおけば1ページで完結させることもできるね。

まあそこら辺は応用ということで。

おまけ:ディレクトリを空にする

「指定したディレクトリの中にファイルが入ってたら削除しますよ」の仕組み。

<?php
//ディレクトリ内削除処理
$results = glob('./dir/*');
if(count($results) > 0):
	array_map('unlink', $results);
endif;
?>

削除条件はファイル数なので、これをそのまま仕込むと仕込んだページを読み込んだら問答無用で削除される。「空にしたい」だけを考えたら、ファイル数カウントすら仕込む必要はないですね。用途に合わないかもしれないから自分に都合のいい発火点に組み込むのがいい。

参考

PHPでファイルアップロードを実装する方法 | UX MILK
PHPでCSVファイルの読み込みから編集や書き出しをする | ITハット
配列内の全ての文字列を一括で置換する方法[PHP] : バヤシタ

コメント

タイトルとURLをコピーしました