【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ファイルを操作する場合でも排他制御やクローズ処理など、fopen関数の基本的な使い方は下記で紹介しているものと同じです。

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

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

fputcsv関数で書き込み実行

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

<?php

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    // 改行を削除
    $_POST['contact'] = preg_replace('/\n|\r|\r\n/', '', $_POST['contact']);

    $filepath = 'data.csv';

    if (!$fp = fopen($filepath, 'ab')) {
        echo 'ファイルが開けませんでした。';
    } elseif (flock($fp, LOCK_EX) == false) {
        echo 'ファイルがロック出来ませんでした。';
    } else {
        fputcsv($fp, $_POST);

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

        // 送信完了後にリダイレクト
        header('Location: /');
    }
}

?>
<!doctype html>
<html lang="ja">

<head>
    <meta charset="utf-8">
    <title>save csv</title>
</head>

<body>
    <h1>save csv</h1>
    <form action="" 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>

fputcsv関数は配列データをCSVフォーマット一行分に変換して書き込むことが出来ます。
(上記例ではフォームからの送信データが変数$_POSTに配列として格納されている)

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

fwrite関数で代用

CSVへの書き込みはfwrite関数を使用しても書き込む事が出来ます。

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

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

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

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

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

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

<?php

$filepath = 'data.csv';
$fp = null;
$list = [];

if (!$fp = fopen($filepath, 'rb')) {
    echo 'ファイルが開けませんでした。';
} elseif (flock($fp, LOCK_SH) == false) {
    echo 'ファイルがロック出来ませんでした。';
}

?>
<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 if ($fp != null) : ?>
            <?php while ($row = fgetcsv($fp)) : ?>
                <tr>
                    <td><?= $row[0] ?></td>
                    <td><?= $row[1] ?></td>
                    <td><?= $row[2] ?></td>
                    <td><?= $row[3] ?></td>
                    <td><?= $row[4] ?></td>
                </tr>
            <?php endwhile; ?>
        <?php endif; ?>
    </table>
</body>
</html>

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

ただし、1回の実行だけでは先頭行のみしか取り出す事が出来ませんので、サンプルのwhile文を使った例のように繰り返し処理を実行して、配列として取り出した行データ(変数$row)を全件データ格納用の配列(変数$list)に格納しています。

文字化けの対処方法

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

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

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

$filepath = '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);
?>
<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 if ($tmp != null) : ?>
            <?php while ($row = fgetcsv($tmp)) : ?>
                <tr>
                    <td><?= $row[0] ?></td>
                    <td><?= $row[1] ?></td>
                    <td><?= $row[2] ?></td>
                    <td><?= $row[3] ?></td>
                    <td><?= $row[4] ?></td>
                </tr>
            <?php endwhile; ?>
        <?php endif; ?>
    </table>
</body>
</html>

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

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

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

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

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

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

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

<?php

$filepath = 'data.csv';

$csvcontents = file_get_contents($filepath);

$csvlist = nl2br($csvcontents);

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

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

    $values = explode(",", $row);

    list($subject, $name, $kana, $contact, $mail) = $values;
}

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

Follow me!

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

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