PHPのファイル操作クラス&関数まとめ
- 公開日
- 更新日
- カテゴリ:Basics
- タグ:PHP,SplFileObject,Basics

PHP でファイル操作を行う、例えばファイルの内容を読み込んでそれについて処理を行ったり、ファイルを作成してその中に書き込みを行ったりなどがありますが、その為にはどんな関数やクラスを用いたら処理が行えるでしょうか。
今回は、外部ライブラリは不要で利用できる PHP の基本的なファイル操作クラスや関数を用いてファイル操作を行っていきます。
Contents
- 開発環境
- 基本的なファイルの読み出し
- CSV/TSV ファイルの読み込み
- ファイルへの書き込み
- CSV/TSV ファイルへの書き込み
- file_get_contents()/file_put_contents()
- SplFileObject クラス
開発環境
今回の開発環境に関しては以下の通りです。
- Linux CentOS 7
- Apache 2.4
- PHP 7.2
デモでは PHP7 を使用しますが、最低でも PHP5.1 以上であれば進めていけます。
基本的なファイルの読み出し
まずは最も基本的なファイルの読み込みからです。以下の関数を利用する事でファイルの読み込みを行う事が出来ます。
- fopen()
- ファイルもしくは URL を開く
- fgets()
- ファイルポインタから 1行取得する
- feof()
- ファイルポインタがファイルの後端に達しているかどうか調べる
- fclose()
- オープンされたファイルポインタをクローズする
これらを利用して、以下のようにファイルを読み込み出力する事が出来ます。
// ファイルを開く
$handle = fopen("./sample1.txt", "rb");
// ループで出力
while ($data = fgets($handle)) {
var_dump($data);
}
// ファイルをクローズする
fclose($handle);
fopen() メソッドの第一引数にファイルパスを、第二引数にはアクセス形式を指定しています。読み込みなので「rb 」を指定します。
アクセス形式を簡単にまとめると以下になります。
モード | アクセス | ファイルポインタ | コンテンツ | ファイル無し | ファイル有り |
---|---|---|---|---|---|
r | 読み込み | 先頭 | |||
r+ | 読み込み/書き出し | 先頭 | |||
w | 書き出し | 先頭 | クリア | 作成する | |
w+ | 読み込み/書き出し | 先頭 | クリア | 作成する | |
a | 書き出し | 終端(常に追記) | 作成する | ||
a+ | 読み込み/書き出し | 終端(常に追記) | 作成する | ||
x | 書き込み | 先頭 | 作成する | 失敗(※ 1) | |
x+ | 読み込み/書き出し | 先頭 | 作成する | 失敗(※ 1) | |
c | 書き込み | 先頭(常に追記) | 作成する | ||
c+ | 読み込み/書き出し | 先頭(常に追記) | 作成する |
- ※ 1 「x 」と「x+」の場合はファイルが既に存在した場合に fopen() は失敗し E_WARNING レベルのエラーを発生させます。
- ※ PHP7 より「e 」モードが追加されましたがここでは割愛します。
また、アクセス形式について公式では、互換性維持のために fopen() でファイルをオープンする時は常に「b 」フラグを指定することを推奨しています。つまりは、読み込みなら「rb 」書き込みなら「wb 」や「ab 」のように指定するのが良いです。
そして、while 文でループし1行ずつ出力を行っていますが、その際の評価式は「fgets() メソッドによって 1行データが取得出来たかどうか」になっています。取得できない=最後まで取得済み、もしくはエラーの場合はループが終了します。
そして最後に、fclose() メソッドでファイルをクローズします。
また、while 文だけでなく for 文でループ処理を行えます。
for ($data = fgets($handle); !feof($handle); $data = fgets($handle)) {
var_dump($data);
}
1行取得し、ファイルポインタの終端に達していなければ再度取得する。という流れでループが行われます。
1行取得と HTML タグ除去
fgets() とは別に fgetss() という関数があります。1文字違いがとてもややこしい関数ですが、このメソッドはファイルポインタから 1行取り出し、コンテンツの HTML タグを取り除きます。
例えば、以下のようなテキストファイルを用意しました。
- sample.txt
-
<p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p>
P タグで囲まれたリストですが、これを fgetss() で取り出すと結果は以下になります。
$handle = fopen("./sample.txt", "rb");
while ($data = fgetss($handle)) {
print_r($data);
}
// => 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
fclose($handle);
ちなみに、以下のようにする事で除去する HTML タグを除外する事ができます。
$data = fgetss($handle, 100, "<p><a>");
第二引数には除去対象とするデータ長を、第三引数には除去を行わない HTML タグを指定します。
CSV/TSV ファイルの読み込み
CSV や TSV ファイルを読み込む場合は fgetcsv() を使います。
// CSVの読み込み
$handle = fopen("./sample3.csv", "rb");
// 1行の情報を配列として取得する
while ($data = fgetcsv($handle)) {
print_r($data);
}
fclose($handle);
ファイルをオープンする部分は通常と同じですが、ファイルポインタから1行取得する時に、fgetcsv() を使う事で、カンマ区切りである CSV の行データを配列として取得してくれます。
また、TSV ファイルを処理したい場合は第二・第三引数を指定します。
// TSV
$handle = fopen("./sample3.tsv", "rb");
while ($data = fgetcsv($handle, 1000, "\t")) {
print_r($data);
}
fclose($handle);
第二引数には対象とする1行のデータ長を、第三引数にはデミリタとしてタブ「\t 」を指定する事で、タブ区切りである TSV ファイルを読み込む事が出来ます。
尚、CSV ・ TSV に限らず、ファイル内コンテンツに日本語などのマルチバイト文字を含む場合でファイルが UTF-8 ではない場合は文字化けするので、文字コードの変換を行ってからデータを処理します。
$data = fgetcsv($handle);
// Shift-JISのCSV/TSVファイルを処理する場合はUTF-8へ変換を行う
mb_convert_variables('UTF-8', 'sjis-win', $data);
ファイルへの書き込み
ファイルへ書き込みを行うには fwrite() もしくは fputs() を利用します。 fputs() は fwrite() のエイリアスなので、どちらを使っても同じです。
// 書き込みモードでオープン
$handle = fopen($file_path, "wb");
$num1 = mt_rand();
// 書き込み(1回目)
fwrite($handle, "{$num1}\r\n");
$num2 = mt_rand();
// 書き込み(2回目)
fwrite($handle, "{$num2}\r\n");
// クローズ
fclose($handle);
書き込みモードでファイルをオープンした後、ランダムに生成した乱数を fwrite() で書き込んでいます。これで2行書き込みが行われた事になります。
CSV/TSV ファイルへの書き込み
CSV や TSV ファイルへ書き込みを行う場合は fputcsv() を使います。
// 書き込みモードでオープン
$handle = fopen($file_path, "wb");
// 書き込む行データ
$record = ['apple', 'orange', 'lemon', 'plum'];
// 書き込み
fputcsv($handle, $record);
// ファイルをクローズ
fclose($handle);
書き込む行データを配列として fputcsv() へ渡す事で書き込みが行われます。
もちろん、日本語などのマルチバイト文字を扱う場合は UTF-8 から Shift-JIS へ文字コードの変換を行う事で文字化けは起こりません。
$record = ['庭に', '赤い', '花が', '咲いた'];
// 文字コードを Shift-JIS へ変換
mb_convert_variables('sjis-win', 'UTF-8', $record);
// 書き込み
fputcsv($handle, $record);
TSV ファイルへの書き込みを行う場合は、fputcsv() の第三引数でタブのデミリタを指定する事でタブ区切りでの書き込みが行われます。
// 書き込みモードでオープン
$handle = fopen($file_path, "wb");
// 書き込む行データ
$record = ['apple', 'orange', 'lemon', 'plum'];
// デミリタをタブに指定して書き込む
fputcsv($handle, $record, "\t");
// ファイルをクローズ
fclose($handle);
file_get_contents()/file_put_contents()
ローカルやリモートのファイル内容を文字列として読み込んだり書き込んだりするには、file_get_contents() や file_put_contents()関数を使います。
ファイルの内容を文字列としてファイルに読み込むには、file_get_contents関数を使います。
$file = file_get_contents("./sample.txt");
echo $file;
// => 1 2 3 4 5 6 7 8 9 10
指定したファイルの内容を全て文字列として読み込んでいます。
反対に、データをファイルへ書き出すには、file_put_contents()関数を使います。
$file_path = "./sample.txt";
// ファイルに書き込む
file_put_contents($file_path, "test write");
SplFileObject クラス
SplFileObject クラスは、ファイルをオブジェクト指向で扱う為のクラスで、SPL(Standard PHP Library)拡張モジュールのファイル操作クラスです。
ちなみに SPL(Standard PHP Library)は、標準的な処理の為のインターフェイスやクラスを集めた拡張モジュールです。 PHP 5.0.0 以降はデフォルトで組み込まれています。
基本的なデータ読み出し
まずは、基本的なテキストファイルからのデータ読み出しです。
$file = new SplFileObject("./sample.txt");
foreach ($file as $line) {
print_r($line);
}
// => 1 2 3 4 5 6 7 8 9 10
コンストラクタにファイルパスを渡し、SplFileObject クラスをインスタンス化します。これだけであとは forearch でループさせればデータを1行ずつ読み出す事が出来ます。
CSV ファイルのデータを読み出す
CSV ファイルのデータを読み出すには以下のように記述します。
$file = new SplFileObject("./sample.csv");
$file->setFlags(
SplFileObject::READ_CSV |
SplFileObject::READ_AHEAD |
SplFileObject::SKIP_EMPTY |
SplFileObject::DROP_NEW_LINE
);
foreach ($file as $line) {
// マルチバイトを扱う場合は文字コードをUTF-8へ変換する
mb_convert_variables('UTF-8', 'sjis-win', $line);
echo'<pre>'; print_r($line); echo'</pre>';
}
setFlags() メソッドで CSV を読み出す為の設定を行っています。引数に渡しているのは SplFileObject クラスの定数です。
READ_CSVCSV 列として行を読み込むREAD_AHEAD 先読み/巻き戻しで読み出す SKIP_EMPTY 空行は読み飛ばす DROP_NEW_LINE行末の改行を読み飛ばすフラグセットを行ったら、あとは通常通りループで回す事で行単位で配列を取得できます。
Array
(
[0] => 1 月 1 日
[1] => 1 月 2 日
[2] => 1 月 3 日
[3] => 1 月 4 日
[4] => 1 月 5 日
)
Array
(
[0] => 2 月 1 日
[1] => 2 月 2 日
[2] => 2 月 3 日
[3] => 2 月 4 日
[4] => 2 月 5 日
)
Array
(
[0] => 3 月 1 日
[1] => 3 月 2 日
[2] => 3 月 3 日
[3] => 3 月 4 日
[4] => 3 月 5 日
)
TSV ファイルのデータを読み出す
CSV ファイルはカンマ区切りですが、TSV ファイルはタブ区切りです。基本的な記述は CSV と同じですが、TSV ファイルを読み出す時は setCsvControl() メソッドでデミリタをタブに切り替えるだけです。
$file = new SplFileObject("./sample.tsv");
$file->setFlags(
SplFileObject::READ_CSV |
SplFileObject::READ_AHEAD |
SplFileObject::SKIP_EMPTY |
SplFileObject::DROP_NEW_LINE
);
// デミリタをタブ指定へ変更し、TSV処理へ変更
$file->setCsvControl("\t");
foreach ($file as $line) {
// マルチバイトを扱う場合は文字コードをUTF-8へ変換する
mb_convert_variables('UTF-8', 'sjis-win', $line);
print_r($line);
}
データの書き出し
SplFileObject クラスでファイルにデータを書き出すには以下のようにします。
$file_path = "./write.txt";
$file = new SplFileObject($file_path, "wb");
$file->fwrite("test data");
コンストラクタの第二引数に書き込みのアクセス形式を渡してインスタンス化を行います。
あとは fwrite() メソッドで書き込みを行います。
CSV ファイルへ書き出すには、fputcsv() メソッドを使います。
$file_path = "./write.csv";
$file = new SplFileObject($file_path, "wb");
$data = [
["1", "1-1", "1-2", "1-3", "1-4"],
["2", "2-1", "2-2", "2-3", "2-4"],
["3", "3-1", "3-2", "3-3", "3-4"],
];
foreach ($data as $d) {
$file->fputcsv($d);
}
マルチバイトを扱う場合は文字コードを UTF-8 へ変換します。
$file_path = "./write.csv";
$file = new SplFileObject($file_path, "w");
$data = [
["1", "おはよう", "こんにちは", "こんばんは", "おやすみ"],
["2", "庭に", "赤い", "花が", "咲いた"],
["3", "Good morning", "Hello", "Good evening", "Good night"],
];
foreach ($data as $line) {
mb_convert_variables('sjis-win', 'UTF-8', $line);
$file->fputcsv($line);
}
TSV ファイルへの書き出しも、基本は CSV と同じです。読み込みと同じように、setCsvControl() メソッドでデミリタをタブに切り替えて書き込みを行います。
$file_path = "./write.tsv";
$file = new SplFileObject($file_path, "wb");
$file->setCsvControl("\t");
$data = [
["1", "1-1", "1-2", "1-3", "1-4"],
["2", "2-1", "2-2", "2-3", "2-4"],
["3", "3-1", "3-2", "3-3", "3-4"],
];
foreach ($data as $d) {
$file->fputcsv($d);
}
まとめ
ファイル操作は PHP の中でも基本的な処理ですが、実務で実装する場合にはデータを書き出したり読み出したりと、重要な機能になります。適切な処理をお行い、安定した機能を実装できるように基本をしっかり押さえておきましょう。