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

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

PHPでfopen関数を使用しないでファイル読み書きを行える、
file_get_contentsとfile_put_contentsについて紹介します。

(fopen関数については下記参照)

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

環境:PHP 7.4.8

file_get_contents、file_put_contentsを使用することでfopen関数でファイルリソースを取得することなくファイル操作を行えるようになります。

file_get_contents
ファイルからデータを読み込む
file_put_contents
ファイルへデータを書き込む

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

メリット

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

これらの関数はファイル操作の際にfopen関数を実行する必要がありません。
fopenを使ってファイル操作を行う場合は通常、

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

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

(fopenでファイル操作)

<?php

$filepath = '/Users/ken/Sites/datas/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 = '/Users/ken/Sites/datas/data.txt';

$contents = file_get_contents($filepath);

デメリット

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

これらのデメリットについて

書き込みを実行するfile_put_contentsはオプションとして排他ロック機能を実現するフラグLOCK_EXを付与することが出来ますが、
PHP5.2.4までのバージョンではこの排他ロックの挙動に不具合があり、ロックに失敗した際にファイルの内容を破棄してしまうことがあるようです。

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

file_put_contents() LOCK_EX flag is useless with advisory locking

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

これらのメリット・デメリットを把握した上でシステムのユーザ規模や要件などケースバイケースによってfopen関数による実装と使い分ける必要があります。

以降はfile_get_contents、file_put_contentsを使用したファイル読み/書き操作の実装例を紹介します。

file_get_contentsでデータを読み込む

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

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

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

<?php

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

$contents = file_get_contents($filepath);

echo nl2br($contents);

file_get_contentsはファイルの内容全てを一度に読み取り、それを文字列として返します。
(nl2br関数は改行文字をbrタグに変換します)

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

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

<?php

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

$contents = file_get_contents($filepath);

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

$id = 1;

foreach($rows as $row)
{
    if($row == '')
    {
        continue;
    }
    echo $id.' : '.$row."<br>";
    $id++;
};

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

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

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

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

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

他、CSVからのデータ取得はfgetcsv関数を使用する方法もあります。
(下記記事で紹介しています)

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

file_put_contentsでデータを書き込む

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

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

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

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

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

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

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

パーミッション(権限)設定
fopenでのfwriteと同様、対象ファイルとファイルを保存するディレクトリパスにPHPが書き込める権限が必要です。

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

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

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

(フォーム)

<!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="/fileput.php" method="POST">
<p>入力: <input type="text" name="text"></p>
<p><button type="submit">送信</button></p>
</form>
</body>
</html>

(実行ファイル)

<?php
// fileput.php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    if($_POST['text'] != '')
    {
        $filepath = '/Users/ken/Sites/datas/data.txt';
    
        $data = $_POST['text']."\n";

        $result = file_put_contents($filepath, $data, LOCK_EX | FILE_APPEND);
    
        if($result)
        {
            echo "success.";
        }
        else
        {
            echo "fail.";
        }
    }
    else
    {
        echo '<p style="color:red">入力してください</p>';
    }

}

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

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

(フォーム)

<!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="/fileputcsv.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
// fileputcsv.php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    if(in_array("", $_POST, true) == false)
    {
        $filepath = '/Users/ken/Sites/datas/data.csv';
        
        $line = implode(',' , $_POST);
        
        $data = $line."\n";
        
        $result = file_put_contents($filepath, $data, LOCK_EX | FILE_APPEND);
        
        if($result)
        {
            echo "success.";
        }
        else
        {
            echo "fail.";
        }
    }
    else
    {
        echo '<p style="color:red">全て入力してください</p>';
    }
}

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

Follow me!