【PHP】fopen関数でファイル操作 ①テキストファイル編

fopen関数でファイルの読み書きを行う

PHPでファイルの読み込みと書き込み操作を実現出来るfopen関数について、
テキストファイル(.txt)を例に実装方法を紹介します。

環境:PHP 7.4.8

ファイル操作の基本的な流れ

fopen関数を使用したファイル操作の基本的な流れは読み込み、書き込み時共に以下のようになります。

ファイルを開く (fopen)

ファイルをロックする (flock)

読み込み / 書き込み

ファイルのロックを解除する

ファイルを閉じる (fclose)


ファイルを開く(fopen)

読み書きどちらの場合も最初にfopen関数で対象のファイルを開き、操作が終わったらfclose関数でファイルを閉じるまでが一連の操作となります。

fopenのモード指定

fopen関数は以下のように記述し、実行します。

fopen(第一引数:ファイルパス, 第二引数:モード)

  • 第一引数: 環境に存在するファイルの場所を絶対パスまたは相対パスで指定
  • 第二引数: ファイルを開くモードを指定

第二引数に指定するモードは下図のように10種類存在します。

モード読み込み/書き込みファイルが存在しない場合ファイルが存在する場合ポインタの位置
rb読み込み専用エラー開く先頭
r+b読み込み/書き込みエラー開く先頭
wb書き込み専用新規作成ファイルを空にして開く先頭
w+b読み込み/書き込み新規作成ファイルを空にして開く先頭
ab書き込み専用(追記)新規作成開く終端
a+b読み込み/書き込み(追記)新規作成開く終端
xb書き込み専用新規作成エラー先頭
x+b読み込み/書き込み新規作成エラー先頭
cb書き込み専用新規作成開く先頭
c+b読み込み/書き込み新規作成開く先頭

種類別に読み書きの目的やファイル作成時の挙動が異なりますが、基本的な用途として主に以下がよく使用されます。

rb 読み込み
wb 書き込み (上書き)
ab 書き込み (追記)

それぞれ「r+b」のように+記号をつけることにより、読み書きどちらも行えるようになります。

bって何?

全てのモードについている「b」の文字ですがこちらは「バイナリモード」を表し、
対象がテキストデータであった場合も互換性を考慮し基本的にはつけておくことが推奨されています。
(bを省いていても基本的には開くことが出来る)

flock関数による排他制御


操作の途中に登場するファイルをロックする操作は排他制御といい、
Webサイトなどで複数のユーザーから同じファイルへ同時にアクセスされる可能性がある場合データの整合性を保つため、
先にファイルを開いたユーザーがそのファイルを閉じるまでは他のユーザーからは操作出来ないようにする処理です。

排他制御はflock関数を使って行い、
読み込み時と書き込み時でそれぞれ共有ロック、排他ロックという方法をモードの指定によって使い分けます。

対象の操作ロックの種類flock関数のモードロックの動作
読み込み共有ロックLOCK_SH他のユーザからは読み込みのみ許可する
書き込み排他ロックLOCK_EX他のユーザからは読み込みも書き込みも許可しない

操作完了時にファイルを閉じる(fclose)

ファイルへ読み書きの操作が完了したらfclose関数を実行して開いたファイルを閉じます。
こちらの操作を行わないと目的完了後もファイルが開いたままになってしまい、他のプロセスで実行することや削除することが出来なくなってしまう場合があります。

以下、fopenを使った具体的な実装方法を読み書き操作別に解説していきます。

ファイルからデータを読み込む(SAMPLE)



fgets関数
を使用してファイルからデータを読み込みます。

fgetsはテキストデータから1行の単位でデータを取得する関数で、下記のようにロジックを組むことで全行分のテキストを読み込むことが出来ます。

ここでは「読み込みのみ」としますので、fopen関数のモード「r」で実行してファイルを開きます。

ファイルを開くことに成功するとfopen関数はファイルリソースを返すのでそれを対象にロックやデータ取得操作を行います。

ファイルを開けなかった場合、fopen関数はfalseを返すので開けなかった場合の処理を分岐することが出来ます。

繰り返しのwhile文の条件にしているfeofは行の最後に達しているかどうかを判定する関数となっており、各行ごとのデータを配列dataに格納していきます。

データの読み込みが完了したらモード「LOCK_UN」でflock関数を実行してファイルのロックを解除し、fcloseで開いているファイルを閉じて処理を終了します。

ファイルへデータを書き込む(SAMPLE)

ファイルへ書き込みを行うためにfwrite関数を使います。

以下のサンプルではフォームから入力された値をテキストファイルの末尾に追加していきます。

フォーム

(フォームから実行)

今回は「書き込み(追記)のみ」としたいのでモード「a」を指定してfopen関数を実行します。

前述のファイル読み込み操作と基本的な流れは同じですが、flock関数には排他ロックの「LOCK_EX」を指定します。

ひとつの書き込みごとに改行したいので、書き込みたいデータの末尾に改行コード(バックスラッシュエヌ)を付けます。

(補足)fflush関数について

書き込み操作においてfflush関数というバッファに溜められた書き込みデータをファイルに出力(フラッシュ)する機能を使う事が出来ます。

連続した大量の書き込み処理時、即座に結果を確認したい場合などに用いられる機能のようですが
本サンプルのようにファイルへの入力データに改行文字を含んでいる場合は自動的にバッファを開放するようですのでとくに利用する必要はなさそうです。

ファイル書き込み時のパーミッション(権限)を設定する

書き込み操作を行う場合はPHPを実行するユーザー、つまりwebサーバ(Apacheなど)のユーザーが対象ファイルの書き込み権限を持っていないと書き込みを実行することが出来ませんのでファイルに対してあらかじめパーミッション設定を行っておく必要があります。

(パーミッションを設定するコマンド)

chmod 666 対象ファイルのパス

もしくは、
chmod 777 対象ファイルのパス

また、書き込み対象ファイルがまだ存在していないとき、モード「a」はファイルを新規作成しますが、その場合ファイルを格納するディレクトリに対して実行&書き込み権限がないといけませんのでそちらも設定しておきます。

chmod 777 ディレクトリパス

(Macの場合、Finderからアクセス権限を変更することも出来ます)

 

データの書き込み、読み込みどちらも行う (SAMPLE)

サンプルでは読み書き可能なモードでファイルを開き、
フォームから入力したデータの書き込みとデータ一覧(直後の書き込みも含む)の読み込みを順に行います。

(フォームから利用)

モードを読み書き可の「a+」としてfopenを実行し、リクエストがPOSTの時のみ書き込み処理をする仕組みとなっています。

rewind関数でポインタを戻す


ポインタとは…
ファイルの中で現在指している位置のこと
(fopenで指定するモードによって先頭か終端かのどちらかになる)


fopen関数のモード「a+b」でファイルを開いた場合、ポインタはファイルの終端となるのでそのまま処理を進めてしまうと以降のfgets関数で読み込めるデータが無く、何も表示する事が出来ません。

fwriteでデータを書き込んだ後にrewind関数を実行し、終端の位置のままとなっているポインタをファイルの先頭に戻すことにより、以降の処理でファイルの先頭からデータを読み込む事が可能となります。

Follow me!

【PHP】fopen関数でファイル操作 ①テキストファイル編” に対して2件のコメントがあります。

コメントは受け付けていません。