PHPでファイル出力する方法や基本的な書き方について

採用はこちら

目次

PHPでファイル出力する方法

PHPでは、テキストやCSV、JSON、ログなどのデータをファイルとして保存できます。

もっとも簡単な方法はfile_put_contents()を使う方法です。

一方で、ファイルを開いて細かく制御したい場合は、fopen()fwrite()fclose()を組み合わせます。

用途によって使い分けるのが基本です。

file_put_contents()でファイルを出力する

単純に文字列をファイルへ保存するだけなら、file_put_contents()が便利です。

<?php

file_put_contents('sample.txt', 'Hello PHP');

このコードを実行すると、sample.txtというファイルが作成され、その中に次の文字列が保存されます。

Hello PHP

すでに同じ名前のファイルが存在する場合は、基本的に内容が上書きされます。

変数の内容をファイルへ出力する

固定文字列だけでなく、変数に格納した値もファイルへ保存できます。

<?php

$message = 'PHPでファイルを作成しました。';

file_put_contents('sample.txt', $message);

プログラムによって生成したデータをファイルとして残したい場合にも利用できます。

PHPでファイルを上書きする方法

file_put_contents()を通常どおり使用すると、既存ファイルがある場合は内容が上書きされます。

<?php

file_put_contents(
    'sample.txt',
    '新しい内容です。'
);

たとえば、もともと次の内容が保存されていたとします。

古い内容です。

コードを実行すると、内容は次のようになります。

新しい内容です。

既存データを残したい場合は、上書きではなく追記を使用します。

PHPでファイルに追記する方法

既存ファイルの末尾へ新しい内容を追加したい場合は、FILE_APPENDを使用します。

FILE_APPENDを使って追記する

<?php

file_put_contents(
    'log.txt',
    '新しいログです。' . PHP_EOL,
    FILE_APPEND
);

繰り返し実行すると、次のように内容が追加されます。

新しいログです。
新しいログです。
新しいログです。

ログファイルや処理履歴を保存する場合によく使われます。

PHPで改行してファイル出力する方法

複数行のデータを書き込みたい場合は、改行文字を含めます。

PHP_EOLを使用する

PHPではPHP_EOLという定数を利用できます。

<?php

$text = '1行目' . PHP_EOL;
$text .= '2行目' . PHP_EOL;
$text .= '3行目' . PHP_EOL;

file_put_contents('sample.txt', $text);

出力結果は次のようになります。

1行目
2行目
3行目

PHP_EOLはPHPが動作している環境に対応した行末文字を表します。

ただし、外部システムとのデータ交換などで改行コードが指定されている場合は、"\n""\r\n"を明示したほうが適切です。

fopen()とfwrite()でファイル出力する方法

より細かなファイル操作をしたい場合は、fopen()fwrite()fclose()を使用します。

基本的な流れは次のとおりです。

fopen()
↓
fwrite()
↓
fclose()

fopen()でファイルを開く

<?php

$handle = fopen('sample.txt', 'w');

fopen()の第2引数には、ファイルをどのように開くかを示すモードを指定します。

fwrite()で書き込む

<?php

$handle = fopen('sample.txt', 'w');

if ($handle !== false) {
    fwrite($handle, 'Hello PHP');
    fclose($handle);
}

fwrite()を使うと、開いたファイルへデータを書き込めます。

fclose()でファイルを閉じる

書き込みが終わったら、fclose()でファイルを閉じます。

fclose($handle);

file_put_contents()と違い、ファイルを開く処理と閉じる処理を自分で管理する必要があります。

fopen()のモードの種類

fopen()では、用途に応じてモードを使い分けます。

wモード

wは書き込み用です。

$handle = fopen('sample.txt', 'w');

ファイルが存在しない場合は新しく作成されます。

すでに存在している場合は、内容が切り詰められます。

aモード

aは追記用です。

$handle = fopen('sample.txt', 'a');

既存内容を残したまま、末尾へデータが追加されます。

xモード

xは新しいファイルを作成するときに使用します。

$handle = fopen('sample.txt', 'x');

すでに同名ファイルが存在する場合は失敗します。

既存ファイルを誤って上書きしたくない場合に便利です。

cモード

cは、ファイルが存在しなければ作成し、存在していても自動的に内容を切り詰めないモードです。

$handle = fopen('sample.txt', 'c');

ロックを取得してからファイル内容を変更したい場合などに利用できます。

fwrite()で複数回書き込む方法

fwrite()は、一つのファイルに対して複数回実行できます。

<?php

$handle = fopen('sample.txt', 'w');

if ($handle !== false) {
    fwrite($handle, '名前:山田太郎' . PHP_EOL);
    fwrite($handle, '年齢:30歳' . PHP_EOL);
    fwrite($handle, '職業:エンジニア' . PHP_EOL);

    fclose($handle);
}

出力結果は次のようになります。

名前:山田太郎
年齢:30歳
職業:エンジニア

大量のデータを少しずつ書き込みたい場合は、fwrite()を利用する方法が適しています。

PHPでCSVファイルを出力する方法

CSVを出力するときは、fputcsv()を利用できます。

CSVでは、カンマや引用符を適切に処理する必要があるため、自分で文字列を連結するよりもfputcsv()を使うほうが安全です。

fputcsv()の基本的な書き方

PHP 8.4以降を考慮する場合は、escape引数を明示しておくのが適切です。

<?php

$handle = fopen('users.csv', 'w');

if ($handle !== false) {
    fputcsv(
        $handle,
        ['名前', '年齢', '職業'],
        ',',
        '"',
        ''
    );

    fputcsv(
        $handle,
        ['山田太郎', 30, 'エンジニア'],
        ',',
        '"',
        ''
    );

    fputcsv(
        $handle,
        ['佐藤花子', 28, 'デザイナー'],
        ',',
        '"',
        ''
    );

    fclose($handle);
}

fputcsv()を利用すると、CSV形式に合わせて値を適切に処理しながら出力できます。

PHP 8.4以降では、escape引数をデフォルトのまま省略する使い方が非推奨になっているため、明示的に指定しておくほうが現在のPHPに適した書き方です。

PHPでJSONファイルを出力する方法

配列やオブジェクト形式のデータを保存したい場合は、JSON形式もよく使われます。

json_encode()とfile_put_contents()を組み合わせる

<?php

$data = [
    'name' => '山田太郎',
    'age' => 30,
    'job' => 'エンジニア',
];

$json = json_encode(
    $data,
    JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
);

file_put_contents('user.json', $json);

出力結果は次のようになります。

{
    "name": "山田太郎",
    "age": 30,
    "job": "エンジニア"
}

JSON_UNESCAPED_UNICODEを指定すると、日本語がUnicodeエスケープされず読みやすい状態で保存されます。

JSON_PRETTY_PRINTを指定すると、インデント付きで整形されます。

ファイル出力に成功したか確認する方法

ファイルへの書き込みは必ず成功するとは限りません。

そのため、戻り値を確認することが重要です。

file_put_contents()の戻り値を確認する

<?php

$result = file_put_contents(
    'sample.txt',
    'Hello PHP'
);

if ($result === false) {
    echo 'ファイルの書き込みに失敗しました。';
} else {
    echo 'ファイルの書き込みに成功しました。';
}

file_put_contents()は、成功すると書き込んだバイト数を返します。

失敗するとfalseを返します。

そのため、

if (!$result) {

ではなく、

if ($result === false) {

と厳密比較するのが適切です。

ファイルが存在するか確認する方法

ファイルの存在確認にはfile_exists()を使用できます。

file_exists()を使用する

<?php

if (file_exists('sample.txt')) {
    echo 'ファイルがあります。';
} else {
    echo 'ファイルがありません。';
}

既存ファイルがある場合だけ処理したい場合などに利用できます。

保存先ディレクトリを指定する方法

実際のWebアプリケーションでは、PHPファイルと同じディレクトリではなく、専用の保存先を用意するケースが多くあります。

__DIR__を利用する

<?php

$filePath = __DIR__ . '/logs/app.log';

file_put_contents(
    $filePath,
    'ログデータ'
);

__DIR__は、そのPHPファイルが存在しているディレクトリを表します。

相対パスだけを使うよりも保存場所を把握しやすくなります。

保存先ディレクトリが存在しない場合

ファイルを書き込もうとしても、保存先のディレクトリそのものが存在しなければ失敗します。

mkdir()でディレクトリを作成する

<?php

$directory = __DIR__ . '/logs';

if (!is_dir($directory)) {
    mkdir($directory, 0755, true);
}

file_put_contents(
    $directory . '/app.log',
    'ログデータ'
);

mkdir()を使えば、必要に応じてディレクトリを作成できます。

ただし、実際のアクセス権限はOSやサーバー設定、umaskなどの影響も受けます。

複数の処理から同じファイルへ書き込む場合

Webアプリケーションでは、複数のリクエストが同時に同じファイルへ書き込む可能性があります。

その場合は、排他制御を検討する必要があります。

LOCK_EXを使用する

file_put_contents()では、LOCK_EXを指定できます。

<?php

file_put_contents(
    'log.txt',
    'ログデータ' . PHP_EOL,
    FILE_APPEND | LOCK_EX
);

これにより、書き込み処理中に排他的なロックを取得できます。

flock()を使用する

さらに細かく制御したい場合はflock()を使用します。

<?php

$handle = fopen('log.txt', 'a');

if ($handle !== false) {
    if (flock($handle, LOCK_EX)) {
        fwrite(
            $handle,
            'ログデータ' . PHP_EOL
        );

        flock($handle, LOCK_UN);
    }

    fclose($handle);
}

LOCK_EXは排他的ロックです。

一方、LOCK_SHを使用すると共有ロックになります。

flock()は基本的にアドバイザリロックであるため、対象ファイルを扱う他の処理側でもロックを考慮する必要があります。

wモードと排他ロックを組み合わせる場合の注意点

fopen()wモードで開く場合は注意が必要です。

ロック取得前に内容が消える可能性がある

次のようにすると、

$handle = fopen('sample.txt', 'w');

flock($handle, LOCK_EX);

fopen()の時点ですでに既存ファイルが切り詰められます。

つまり、ロックを取得する前に内容が空になる可能性があります。

c+モードを利用する方法

ロック取得後に安全に内容を置き換えたい場合は、たとえば次のようにできます。

<?php

$handle = fopen('sample.txt', 'c+');

if ($handle !== false) {
    if (flock($handle, LOCK_EX)) {
        ftruncate($handle, 0);
        rewind($handle);

        fwrite(
            $handle,
            '新しい内容'
        );

        fflush($handle);

        flock($handle, LOCK_UN);
    }

    fclose($handle);
}

この方法なら、ロック取得後に既存内容を削除して新しい内容を書き込めます。

fwrite()の戻り値も確認する

fwrite()にも戻り値があります。

重要なファイルを扱う場合は、書き込み結果を確認したほうが安全です。

fwrite()のエラーを確認する

<?php

$handle = fopen('sample.txt', 'w');

if ($handle !== false) {
    $result = fwrite(
        $handle,
        'Hello PHP'
    );

    if ($result === false) {
        echo '書き込みに失敗しました。';
    }

    fclose($handle);
}

fwrite()は成功すると書き込んだバイト数を返し、失敗した場合はfalseを返します。

PHPでファイル出力できない主な原因

コードに問題がなくても、環境によってファイルを書き込めない場合があります。

保存先ディレクトリが存在しない

たとえば、

file_put_contents(
    __DIR__ . '/logs/app.log',
    'Hello'
);

としていても、logsディレクトリが存在しなければ書き込みに失敗します。

書き込み権限がない

PHPを実行しているユーザーに保存先への書き込み権限がない場合も失敗します。

ファイル出力できないときは、主に次の点を確認します。

  • ファイルパスが正しいか
  • 保存先ディレクトリが存在するか
  • PHP実行ユーザーに書き込み権限があるか
  • PHPやWebサーバー側の制限に抵触していないか
  • ディスク容量などに問題がないか

PHPでファイル出力するときのセキュリティ

Webアプリケーションでは、ファイル出力そのものだけでなく、保存先の安全性にも注意する必要があります。

ユーザー入力をそのままファイル名にしない

次のようなコードは避けたほうがよいでしょう。

<?php

$fileName = $_GET['file'];

file_put_contents(
    $fileName,
    'データ'
);

外部入力をそのままファイルパスとして利用すると、意図しない場所へファイルを書き込まれる危険があります。

たとえば、../などを利用したパストラバーサルへの対策も必要になります。

ファイル名をプログラム側で生成する

できるだけ保存先を固定し、ファイル名もプログラム側で生成すると安全性を高められます。

<?php

$id = 123;

$fileName = __DIR__
    . '/data/user_'
    . $id
    . '.json';

さらに、パスワードやAPIキーなどの機密情報を、Webから直接アクセスできる公開ディレクトリへ安易に保存しないことも重要です。

ファイル出力と画面出力の違い

PHP初心者の場合、echoとファイル出力を混同することがあります。

echoはPHPの出力へ送る

echo 'Hello PHP';

echoは、通常ブラウザなどへ返すPHPの出力として文字列を送ります。

file_put_contents()はファイルへ保存する

file_put_contents(
    'sample.txt',
    'Hello PHP'
);

こちらは、サーバー上のファイルへデータを書き込みます。

つまり、

echo
→ PHPの出力へ送る

file_put_contents()
→ ファイルへ保存する

という違いがあります。

書き込んだファイルを読み込む方法

ファイルの内容を読み込みたい場合には、file_get_contents()を使用できます。

file_get_contents()の基本的な書き方

<?php

$content = file_get_contents('sample.txt');

if ($content !== false) {
    echo $content;
}

file_get_contents()はファイル全体を文字列として取得します。

そのため、簡単なファイル操作では、

file_put_contents()

で保存し、

file_get_contents()

で読み込むという組み合わせがよく使われます。

PHPのファイル出力で覚えておきたい関数

PHPでファイル操作をする場合は、まず代表的な関数を覚えておくと理解しやすくなります。

file_put_contents()

ファイルへデータを書き込みます。

単純なファイル保存では特に使いやすい関数です。

file_get_contents()

ファイル全体を文字列として読み込みます。

fopen()

ファイルを開きます。

fwrite()

開いたファイルへデータを書き込みます。

fclose()

開いているファイルを閉じます。

fputcsv()

CSV形式でデータを書き込みます。

file_exists()

ファイルやディレクトリの存在を確認します。

flock()

ファイルのロックに使用します。

mkdir()

ディレクトリを作成します。

PHP初心者はfile_put_contents()から覚える

PHPのファイル出力を初めて学ぶのであれば、まずはfile_put_contents()から覚えると理解しやすいでしょう。

上書きする場合

file_put_contents(
    'sample.txt',
    'Hello PHP'
);

追記する場合

file_put_contents(
    'sample.txt',
    'Hello PHP' . PHP_EOL,
    FILE_APPEND
);

追記しながら排他ロックする場合

file_put_contents(
    'sample.txt',
    'Hello PHP' . PHP_EOL,
    FILE_APPEND | LOCK_EX
);

より細かな処理が必要になった段階で、fopen()fwrite()fclose()flock()などを覚えていくとよいでしょう。

PHPでファイル出力する方法のまとめ

PHPでファイル出力する場合、単純な書き込みであればfile_put_contents()を利用するのが簡単です。

既存ファイルへの追記にはFILE_APPENDを使用でき、複数の処理から同じファイルへ書き込む可能性がある場合はLOCK_EXなどによる排他制御も検討できます。

一方で、ファイルを開くモードを指定したり、複数回に分けて書き込んだりする場合は、fopen()fwrite()fclose()を使用します。

CSVファイルを作成する場合はfputcsv()、JSONファイルの場合はjson_encode()file_put_contents()を組み合わせる方法が一般的です。

また、実際のWebアプリケーションでは、保存先ディレクトリの存在、書き込み権限、エラー処理、排他制御、外部入力をファイル名に利用するときのセキュリティなども考慮する必要があります。

基本的には、簡単な保存ならfile_put_contents()、細かな制御が必要ならfopen()系の関数と覚えておくと使い分けやすいでしょう。

以上、PHPでファイル出力する方法や基本的な書き方についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次