tmpfileと一時ファイルを後始末まで含めて扱う
tmpfile とは、読み書き用の一時ファイルを開き、fclose するかスクリプト終了時に自動で削除してくれる関数です。消し忘れのゴミが残りません。
tmpfileは閉じれば消える
処理の途中でどうしてもファイルが欲しいけれど、あとに残したくない。そんなときは tmpfile() が便利です。読み書き用のファイルハンドルを返してくれて、fclose() するかスクリプトが終了した時点で自動的に削除されます。消し忘れのゴミが溜まらないのが良いところですね。
$fp = tmpfile();
fwrite($fp, "一時的なデータ\n");
rewind($fp);
echo fread($fp, 1024);
fclose($fp); // ここでファイルは消える
ファイル名を知りたいときは、開いている間に stream_get_meta_data($fp)['uri'] で取れます。ただし閉じた後はもう存在しないので、外部コマンドに渡すような用途では扱いに注意が必要だと思います。
名前が要るならtempnamとsys_get_temp_dir
ハンドルではなく実体のファイルパスが欲しい場合は tempnam() です。一時ディレクトリは sys_get_temp_dir() で取れるので、これを基準にすると環境依存を避けられます。tempnam() は衝突しないファイル名を作って空ファイルまで用意してくれるのがポイントですね。
$path = tempnam(sys_get_temp_dir(), 'exp_');
// 例: /tmp/exp_a1b2c3
file_put_contents($path, $csv);
// 外部コマンドに渡すなど…
unlink($path); // こちらは自分で消す必要がある
tempnam() は自動削除されないので、後始末は自分の責任です。ここが tmpfile() との大きな違いだと思います。
例外が飛んでも消えるように
途中で例外が飛ぶと unlink() に辿り着かず、ゴミが残ります。tempnam() を使うなら try/finally で確実に消す、あるいは残らなくていいなら最初から tmpfile() を選ぶ、という判断になりますね。私は「名前が要らないなら tmpfile、要るなら tempnam + finally」で切り分けています。
$path = tempnam(sys_get_temp_dir(), 'job_');
try {
file_put_contents($path, $payload);
run_external_tool($path); // 例外が飛ぶかもしれない
} finally {
if (is_file($path)) {
unlink($path);
}
}
まとめ
一時ファイルは「誰がいつ消すか」を最初に決めておくのが肝だと思います。ハンドルだけで済むなら自動削除される tmpfile()、実パスが必要なら sys_get_temp_dir() 起点の tempnam() を使い、後者は finally で確実に片付ける。この使い分けができていれば、/tmp にゴミが積もる心配はほぼなくなります。
よくある質問
Q. ファイル名が欲しいときは?
A. 開いている間は stream_get_meta_data($fp)['uri'] で取れます。実パスが要るなら、最初から tempnam() を使うほうが向いています。
Q. tempnam との違いは?
A. tmpfile は自動削除されますが、tempnam は自動削除されないので後始末は自分の責任です。名前が要るなら tempnam、要らないなら tmpfile で切り分けます。
Q. 例外が飛んでもゴミを残したくありません。
A. tempnam を使うなら try/finally で確実に unlink します。残らなくていいなら、最初から tmpfile を選ぶのが楽です。