【PHP】file_get_contents & file_put_contentsによるファイル操作

file_get_contents & file_put_contentsによるファイル操作

PHPでfile_get_contents関数及び、file_put_contents関数を使用したファイル操作の方法を紹介します。

環境:PHP 7.4.8

PHPではファイル操作のためにfopen関数が用意されていますが、file_get_contents、file_put_contentsを使用することで、より手軽にファイル操作を行えるようになります。

fopen関数の使用方法については以下記事を参照ください。

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

file_get(put)_contentsのメリット・デメリット

メリット

  • (fopenに比べ)記述が少なくてカンタン

 

fopenを使ってファイル操作を行う場合は通常、

ファイルを開く → ファイルをロック → ファイルへの読み/書き → ロックの解除 → ファイルを閉じる

といった一連の手順が必要になりますが、file_get(put)_contents実行の際はそれらをひとまとめで行う事が出来ます。

fopen関数を使ったファイル操作の例

<?php

$filepath = 'data.txt';

$fp = fopen($filepath,'a+b');

flock($fp, LOCK_SH);

// read or write

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

file_get_contentsを使用した例

<?php

$filepath = 'data.txt';

$contents = file_get_contents($filepath);

デメリット

  • 旧バージョンで排他ロックの挙動に不具合あり
  • file_get_contentsには排他制御機能がない

これらのデメリットについて前者は書き込みを実行するfile_put_contentsはオプションとして排他ロックを実現するフラグ「LOCK_EX」を付与することが出来ますが、バージョン5.2.4までのPHPではこの排他ロックの挙動に不具合があり、ロックに失敗した際にファイルの内容を破棄してしまうことがあるようです。

PHP公式のバグとして以下のように報告されています。
Bug #43182

file_put_contents() LOCK_EX flag is useless with advisory locking

後者のfile_get_contentsを使用した読み取り操作の場合も対象ファイルへ他のユーザーからの書き込みリクエストが集中した際は想定外の挙動が発生する可能性があるため共有ロックをかけることが推奨されていますが、file_get_contentsにはそもそもロック機能が用意されていません。

これらのデメリットを把握した上でシステムの要件に合わせfopen関数による実装と使い分ける必要があります。

file_get_contentsでデータを読み込む

file_get_contents関数を使用してファイルからデータを取得します。

テキストファイルからデータを読み込む(SAMPLE)

一行ごとにデータが存在するテキストファイルからデータを読み取って表示します。

<?php

$filepath = 'data.txt';

$contents = file_get_contents($filepath);

echo nl2br($contents);

file_get_contentsはファイルの全内容を一度に読み取りそれを文字列として返します。

データ一行ごとに処理を加えたい場合

全てのデータを一度にまとめて読み取りますので、データ一行ごとに処理を行いたい場合は下記のように処理を加える必要があります。

<?php

$filepath = 'data.txt';

$contents = file_get_contents($filepath);

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

$id = 1;

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

    echo $id . ' : ' . $row . "<br>";
    $id++;
};

改行を区切り文字としてexplode関数を実行することで一行分のデータを配列の要素として扱うことが出来ます。

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

CSVファイルからもfile_get_contentsを使用してデータを読み取ることが出来ます。

<?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;

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

配列の要素として取得した一行分のデータをカンマ区切りで更に配列とし、列の値を取り出しています。

file_put_contentsでデータを書き込む

file_put_contents関数を使用してファイルへデータを書き込みます。

file_put_contents関数の基本
実行時に下記のようにパラメータを指定します。

file_put_contents(ファイルパス, 書き込みデータ)

もしくは、
file_put_contents(ファイルパス, 書き込みデータ, オプション)

第一引数 : 書き込むファイルが存在するパス
第二引数 : ファイルに書き込むデータ(文字列)
第三引数 : オプション

オプション挙動
LOCK_EX排他ロックを行う(PHP5.2.4以前不具合あり)
FILE_APPEND書き込みモードを追記にする

オプションは|(パイプ)で繋ぐことで複数付与することが出来ます。

パーミッション(権限)設定
対象ファイルとファイルを保存するディレクトリパスにサーバーから書き込める権限が必要です。

対象のファイルが存在しない場合、file_put_contents実行時に自動的に作成されます。
オプションで追記モードを指定しない限り上書きでの書き込みとなります。

テキストファイルへデータを書き込む

サンプルではフォームからリクエストされたデータをテキストファイルへ追記保存します。

<?php

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if ($_POST['text'] == null) {
        echo '入力してください。';
    } else {
        $filepath = 'data.txt';

        $data = $_POST['text'] . "\n";

        $result = file_put_contents($filepath, $data, LOCK_EX | FILE_APPEND);

        if ($result) {
            echo "書き込みました";
        } else {
            echo "書き込みできませんでした";
        }
    }
}
?>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>file_put_contents test</title>
</head>
<body>
<h1>file_put_contents test</h1>
<form action="" method="POST">
<p>入力: <input type="text" name="text"></p>
<p><button type="submit">送信</button></p>
</form>
</body>
</html>

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

フォームからリクエストされた複数の値を一回分のデータとしてCSVファイルへ追記保存します。

<?php

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (in_array("", $_POST, true) == false) {
        $filepath = 'data.csv';

        $line = implode(',', $_POST);

        $data = $line . "\n";

        $result = file_put_contents($filepath, $data, LOCK_EX | FILE_APPEND);

        if ($result) {
            echo "書き込みました";
        } else {
            echo "書き込みできませんでした";
        }
    } else {
        echo '全て入力してください。';
    }
}
?>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>file_put_contents test</title>
</head>
<body>
<h1>file_put_contents 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>

implode関数でリクエストデータをCSVフォーマットのカンマ区切りに変換し、file_put_contentsへ渡します。

Follow me!