PHP

ファイル操作

テキストやCSVを読み書きして、データをファイルに保存しましょう。

01

パスの基本

ファイルの場所はパスで指定します。実行場所による違いを避けるため、現在のPHPファイルがあるディレクトリを表す __DIR__ を基準にするのがおすすめです。

パスを作るPHP
$filePath = __DIR__ . '/data/message.txt';

if (file_exists($filePath)) {
    echo 'ファイルがあります。';
}
ポイント ファイル名をユーザー入力から直接組み立てると、意図しないファイルへアクセスされる危険があります。
02

ファイルを読む

ファイル全体を文字列として読むなら file_get_contents() が手軽です。失敗時には false が返るため、必ず確認します。

テキストを読むPHP
$filePath = __DIR__ . '/data/message.txt';
$content = file_get_contents($filePath);

if ($content === false) {
    throw new RuntimeException('読み込みに失敗しました。');
}

echo nl2br(htmlspecialchars($content, ENT_QUOTES, 'UTF-8'));

大きなファイルを一行ずつ処理するときは fopen()fgets()fclose() を使うとメモリを節約できます。

一行ずつ読むPHP
$handle = fopen(__DIR__ . '/data/message.txt', 'r');

if ($handle === false) {
    throw new RuntimeException('ファイルを開けません。');
}

while (($line = fgets($handle)) !== false) {
    echo htmlspecialchars($line, ENT_QUOTES, 'UTF-8') . '<br>';
}

fclose($handle);
ポイント fopen() で開いたファイルは、処理が終わったら fclose() で閉じます。
03

ファイルに書く

file_put_contents() は、ファイルの作成と書き込みをまとめて行います。追記には FILE_APPEND、同時書き込みへの対策には LOCK_EX を指定します。

ログを追記するPHP
$logPath = __DIR__ . '/data/app.log';
$line = date('Y-m-d H:i:s') . " ページを表示\n";
$bytes = file_put_contents($logPath, $line, FILE_APPEND | LOCK_EX);

if ($bytes === false) {
    throw new RuntimeException('書き込みに失敗しました。');
}
04

CSVを扱う

CSVはカンマや改行を含む値もあるため、文字列を自分で分割せず fgetcsv()fputcsv() を使います。

CSVを読み込むPHP
$handle = fopen(__DIR__ . '/data/users.csv', 'r');

if ($handle === false) {
    throw new RuntimeException('CSVを開けません。');
}

while (($row = fgetcsv($handle)) !== false) {
    if (count($row) !== 2) {
        continue; // 想定と異なる列数の行は読み飛ばす
    }

    [$name, $email] = $row;
    echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '<br>';
}

fclose($handle);

この例はCSVがUTF-8で保存されていることを前提にしています。表計算ソフトから保存すると文字コードが異なる場合があるため、文字化けしたときは、まずUTF-8形式で保存し直せるか確認しましょう。

Windows版Excelなどで作成したShift_JIS系のCSVを読む必要がある場合は、各行を取得したあとで mb_convert_encoding() を使ってUTF-8へ変換できます。Windows固有の文字を扱えるよう、変換元には SJIS-win を指定します。この関数を使うにはPHPのmbstring拡張が必要です。

文字コードを変換するPHP
$row = array_map(
    static fn ($value) => mb_convert_encoding(
        $value,
        'UTF-8',
        'SJIS-win'
    ),
    $row
);
列数も確認する CSVには空行や列の不足、余分なカンマが含まれることがあります。[$name, $email] = $row; のように分割する前に count($row) を確認すると、存在しない配列要素を読んで警告が出るのを防げます。
05

安全に扱うために

確認すること
  • 読み書きの戻り値が false でないか確認する
  • 保存用ディレクトリだけに適切な書き込み権限を与える
  • 秘密情報や個人情報を公開ディレクトリへ置かない
  • 画面へ出す文字列は htmlspecialchars() でエスケープする

JSON形式なら、配列を json_encode() で保存し、読み込んだ文字列を json_decode() で配列へ戻せます。

PRACTICE

ミニ課題:ひとことメモ

フォームから受け取ったメモを日時と一緒にファイルへ追記し、保存済みのメモを新しい順に表示してみましょう。

条件 空の入力を保存しないこと、表示時にエスケープすること、書き込み結果を確認することの3点を意識してください。