【PHP】fopen関数でファイル操作 ②CSVファイル編

fopen関数でCSVファイルの読み書きを行う

PHPのfopen関数でCSVファイルの読み書き操作を行う方法を紹介します。

環境:PHP 7.4.8

CSVとは…


CSVとはカンマ(,)で区切られた複数の値を一単位(行)のデータとして記録し、
エクセルなど様々なソフトで開いて編集を行うことが出来るファイルフォーマットです。

Comma-Separated Values

subject1,name1,kana1,contact1,example@mail.com
subject2,name2,kana2,contact2,example@mail.com
subject3,name3,kana3,contact3,example@mail.com
subject4,name4,kana4,contact4,example@mail.com

エクセルなどの表計算ソフトではカンマ一区切りごとにセルの値として表示します。

CSVファイルを操作する場合でも排他制御クローズ(fclose)処理など、fopen関数の基本的な使い方は下記で紹介しているものと同じです。

【PHP】fopen関数でファイル操作 ①テキストファイル編

CSVファイルへデータを書き込む(SAMPLE)

fputcsv関数で書き込み実行

fopen書き込みモードで対象のCSVファイルを開き、fputcsv関数を使用して一行分のデータとして値を書き込みます。
サンプルでは入力フォームから送信された情報をCSVファイルに蓄積していきます。

(フォーム)

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>save csv</title>
</head>
<body>
<h1>save csv</h1>
<form action="/savecsv.php" method="POST">
    <p>件名: <input type="text" name="subject"></p>
    <p>お名前: <input type="text" name="name"></p>
    <p>ふりがな: <input type="text" name="kana"></p>
    <p>お問い合わせ内容:</p>
    <textarea name="contact" id="" cols="30" rows="10"></textarea>
    <p>メールアドレス: <input type="text" name="mail"></p>
    <p><button type="submit">送信</button></p>
</form>
</body>
</html>

実行プログラム(送信先)

<?php
// savecsv.php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    // 改行を削除
    $_POST['contact'] = preg_replace('/\n|\r|\r\n/', '', $_POST['contact']);
    
    $filepath = '/Users/ken/Sites/datas/data.csv';
    
    if(!$fp = fopen($filepath,'ab'))
    {
        echo 'ファイルが開けませんでした。';
        return;
    }

    if(flock($fp, LOCK_EX) == false)
    {
        echo 'ファイルがロック出来ませんでした。';
        return;
    }

    fputcsv($fp, $_POST);

    flock($fp, LOCK_UN);
    fclose($fp);

    echo '送信完了';
    return;
}

fputcsv関数は配列データをCSVフォーマット一行分に変換して書き込むことが出来ます。
フォームからの送信データが格納されている変数$_POSTを渡して実行するだけでデータをカンマ区切りでファイルへ記録することが出来ます。

パーミッション設定の確認
CSVファイルとディレクトリに書き込み権限が必要です。

データ蓄積時の注意点
実際のWebサイトでプライバシー情報などを蓄積する場合はファイルの設置場所をドキュメントルート(公開ディレクトリ)の外側にするなど、限られたユーザのみがアクセス出来るような設計にしておく必要があります。


(fwrite関数で代用するには?)

テキストファイルへの書き込みのようにfwrite関数を使用しても書き込む事が出来ます。

$line = implode(',' , $_POST);
fwrite($fp, $line."\n");

implode関数の区切り文字にカンマを指定してデータを取り出すことで、csvのフォーマットに合わせることが出来ます。

CSVファイルからデータを読み込む(SAMPLE)

fgetcsv関数でデータを取り出す

fopen関数の読み取りモードで開いたファイルリソースからfgetcsv関数を使って記録データを取り出します。

以下のサンプルではCSVファイルからデータの一覧を取得し、htmlテーブル形式で表示します。

<?php
$filepath = '/Users/ken/Sites/datas/data.csv';
$fp = fopen($filepath,'rb');

flock($fp, LOCK_SH);

?>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>read csv</title>
</head>
<body>
<table border="1">
    <tr>
        <td>件名</td>
        <td>お名前</td>
        <td>ふりがな</td>
        <td>お問い合わせ内容</td>
        <td>メールアドレス</td>
    </tr>
<?php
while($row = fgetcsv($fp))
{
    list($subject, $name, $kana, $contact, $mail) = $row;
    
    $tableRow = "<tr>";
    $tableRow .= "<td>".$subject."</td>";
    $tableRow .= "<td>".$name."</td>";
    $tableRow .= "<td>".$kana."</td>";
    $tableRow .= "<td>".$contact."</td>";
    $tableRow .= "<td>".$mail."</td>";
    $tableRow .= "</tr>";
    
    echo $tableRow;
};
flock($fp, LOCK_UN);
fclose($fp);
?>
</table>
</body>
</html>

fgetcsv関数を実行すると、CSVファイルの行データを配列として取り出す事が出来ます。

ただし、1回の実行だけでは先頭行のみしか取り出す事が出来ませんので、
while文等で繰り返し処理をして全行分のデータを取り出します。

fgetcsvで取り出したデータが配列として変数rowに格納される ↓
(最下行のデータを取り出すまで処理が繰り返される)

while($row = fgetcsv($fp))
{
    // 処理
};

上記のサンプルでは配列として取り出した行データに対してlist関数を実行して列の値を取り出しています。


文字化けの対処方法

Windows環境(文字コード:Shift-JIS)のエクセルで作成されたCSVファイルを読み込んだ場合、PHPを実行するサーバ側での一般的な文字コードがUTF-8のため文字化けが発生する事があります。

下記のように適切なロケール設定、エンコード変換を使って文字化けに対処します。

<?php
// ロケールを設定
setlocale(LC_ALL, 'ja_JP.UTF-8');

$filepath = '/Users/ken/Sites/datas/data.csv';

// ファイルの内容を全て文字列に読み込む
$file = file_get_contents($filepath);

// Shift JIS to UTF-8
$file = mb_convert_encoding($file, 'UTF-8', 'SJIS');

// 一時ファイルを作成
$tmp = tmpfile();

// 一時ファイルに取り出した内容を書き込む
fwrite($tmp, $file);

// ポインタを先頭に戻す
rewind($tmp);

while($row = fgetcsv($tmp))
{
    list($subject, $name, $kana, $contact, $mail) = $row;
    echo $subject." | ".$name." | ".$kana." | ".$contact." | ".$mail."<br>";
};

fopenは使用せずにfile_get_contents関数を使用してCSVファイルの全てのデータを文字列として取り出し、
mb_convert_encoding関数で文字コードをUTF-8へ変換します。

tmpfile関数を実行することでサーバ上に作成される一時ファイルは、
fopenで開いた通常のファイルと同じようデータ書き込みなどの操作を行う事ができます。

文字コード変換済みのデータを一時ファイルに書き込むことで元のCSVファイルのコピーとなり、
fgetcsv関数での読み取り実行対象として機能します。

書き込み後にrewind関数でポインタを先頭に移動してデータを読み取ります。

一時ファイルはfcloseを実行するか、プログラムが終了することで自動的に削除されます。


fgetcsv関数を使わない方法(SAMPLE)

文字化け等の不具合が上記でも解決出来ない場合、fgetcsvを諦めて下記の方法で代用します。

<?php

$filepath = '/Users/ken/Sites/datas/data.csv';
$csvcontents = file_get_contents($filepath);

$csvlist = nl2br($csvcontents);

$rows = explode("\n", $csvlist);

foreach($rows as $row)
{
    if($row == '')
    {
        continue;
    }

    $values = explode(",", $row);
    
    list($subject, $name, $kana, $contact, $mail) = $values;

    echo $subject." | ".$name." | ".$kana." | ".$contact." | ".$mail;
}

サンプルでは配列の要素に変換した一行分のデータからカンマ区切りを利用してさらに配列を作成し、列の値へ参照します。

Follow me!

【PHP】fopen関数でファイル操作 ②CSVファイル編” に対して1件のコメントがあります。

コメントは受け付けていません。