topic: file-io (read / write / CSV / paths / upload概念)

PHP からローカルファイルを 読む / 書く トピック。設定ファイル・CSV エクスポート・ログ出力など、Web でもバッチでも頻出する基本動作を CLI で完結する形で押さえる。

このトピックで身につくこと

  • file_get_contents / fopen + fgets でテキストを読める
  • file_put_contents で一時ファイルに書ける (追記モードも含む)
  • CSV を fgetcsv / fputcsv で行 × 列の配列として扱える
  • __DIR__ / dirname / basename / pathinfo / scandir でパスとディレクトリを扱える
  • $_FILES / move_uploaded_file を使ったアップロードの 概念 と落とし穴を言える

前提知識の要点

echo が書ける / foreach で配列を回せる / __DIR__ という定数を見たことがある、くらいで OK。クラス・例外は不要。

<?php
// 読み: drill 内固定パスから読む
$text = file_get_contents(__DIR__ . '/tests/data/hello.txt');
echo $text;

// 書き: OS の一時ディレクトリに逃がす
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');
file_put_contents($tmp, "hi\n");
echo file_get_contents($tmp);
unlink($tmp);
▶ 3v4l で実行
  • __DIR__ = この PHP ファイルがあるディレクトリ。cwd に依存しない安全なパスを組める
  • 読みは tests/data/固定パス (コミット済み)、書きは sys_get_temp_dir() の一時ファイルが鉄則

chapter 一覧

# chapter 内容
1 ch01-what-is-file/ ファイル / バイナリ vs テキスト / 文字コード (ドリルなし)
2 ch02-read-file/ file_get_contents / fopen + fgets
3 ch03-write-file/ file_put_contents / FILE_APPEND
4 ch04-csv/ fgetcsv / fputcsv
5 ch05-paths/ __DIR__ / dirname / basename / pathinfo / scandir
6 ch06-upload-concept/ $_FILES / move_uploaded_file の概念 (ドリルなし)

合計 6 chapter / 8 drill / 所要 2〜2.5 時間

採点と「副作用なし」設計

ファイル I/O は 副作用 (ディスク書き換え) を伴うので、grade.php で繰り返し採点してもリポジトリが汚れないように drill を設計してある。

操作 drill 内での扱い
読み込み元 __DIR__ . '/tests/data/foo.txt' のように drill 内固定パス から読む (コミット済み)
書き込み先 tempnam(sys_get_temp_dir(), 'dojo_')OS の一時ディレクトリ に作る (最後に unlink)
期待出力 tests/expected.txt に書く。read 系は中身、write 系は「書いた → 読み返した結果」を echo

つまり「tests/data/ は読み取り専用、書き込みは sys_get_temp_dir()」と覚える。

ch06 (upload) は CLI では本物のアップロードを再現できないため 概念のみ (スライド + README) で扱い、ドリルは置かない。

進め方

  1. 各 chapter の slide.md を読む (4〜5 分)
  2. drill/ の問題を順番に解く (ch01 / ch06 は読むだけ)
  3. 採点: php scripts/grade.php topics/file-io/<chapter>/drill/<drill>/

つまづきポイント

症状 多くの原因
file_get_contentsfalse を返す パスがズレている。__DIR__ . '/...' で組み直す
出力に余計な空行が混ざる 戻り値の末尾に \n が付いている / さらに echo "\n" を足している
fgets ループで末尾 1 行ズレる while (($line = fgets($fp)) !== false) で書く。feof ベースはズレやすい
書き込みが反映されない fopenfwrite の後 fclose 忘れ (バッファが flush されない)
CSV の日本語が文字化け UTF-8 で揃える。Shift_JIS 混入で fgetcsv が崩れる
scandir の出力に . .. が混ざる カレント / 親を表す特殊エントリ。array_diff($files, ['.', '..']) で除く

関連トピック

トピック 関係
array-basic file()fgetcsv の戻り値は配列
loop while (fgets(...)) / foreach で行ごとに処理
web アップロード処理 / CSV ダウンロード機能
db CSV → DB の取り込みバッチ

トピックを並列で参照する全体地図は TOPICS_INDEX.md にある。

案件 (dojo_map.tsv) での参照

topic_slug   chapter_dir
file-io      topics/file-io/ch02-read-file
file-io      topics/file-io/ch03-write-file
file-io      topics/file-io/ch04-csv
file-io      topics/file-io/ch05-paths

slug file-io で参照可。14-file-io / file-io どちらの path でもアクセスできる (シンボリックリンク)。

このレッスンの章

  1. ch01 ch01 — ファイルとは / バイナリ vs テキスト / 文字コード
  2. ch02 ch02 — ファイルを読む
  3. ch03 ch03 — ファイルに書く
  4. ch04 ch04 — CSV を読み書きする
  5. ch05 ch05 — パス操作とディレクトリ走査
  6. ch06 ch06 — ファイルアップロードの概念