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);__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) で扱い、ドリルは置かない。
進め方
- 各 chapter の
slide.mdを読む (4〜5 分) drill/の問題を順番に解く (ch01 / ch06 は読むだけ)- 採点:
php scripts/grade.php topics/file-io/<chapter>/drill/<drill>/
つまづきポイント
| 症状 | 多くの原因 |
|---|---|
file_get_contents が false を返す |
パスがズレている。__DIR__ . '/...' で組み直す |
| 出力に余計な空行が混ざる | 戻り値の末尾に \n が付いている / さらに echo "\n" を足している |
fgets ループで末尾 1 行ズレる |
while (($line = fgets($fp)) !== false) で書く。feof ベースはズレやすい |
| 書き込みが反映されない | fopen → fwrite の後 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 でもアクセスできる (シンボリックリンク)。