PHPでのファイル操作の基本：書き込みと読み込み

この記事では、テキストファイルへの書き込みと、ファイルの読み込み方法について詳しく解説します。

## 実施内容
以下の手順でアクセスログを記録し、表示することを目指します。

- **ログの書き込み:**
PHPを使用して、ユーザーのアクセス日時、スクリプト名、ユーザーエージェント、リンク元URLなどの情報をaccess.logというテキストファイルに追記します。
書き込みにはファイルロックを使用し、データの整合性を保ちます。

- **ログの読み込みと表示:**
fgetsやfile関数を用いて、ログファイルからデータを読み込み、HTMLテーブル形式でウェブページに表示します。

## ファイル操作の基本
### 1. ファイルを開く
PHPでは、`fopen`関数を使ってファイルを開きます。成功するとファイルハンドルが返され、ファイルの操作が可能になります。ファイルを開く際には、以下のモードを指定します。

| モード | 説明 |
|----- | ---- |
|r	| 読み込み専用。ファイルが存在しない場合はエラー。 |
|w	| 書き込み専用。ファイルが存在しない場合は作成、存在する場合は内容を消去。 |
|a	| 追記書き込み専用。ファイルが存在しない場合は作成、存在する場合は末尾に追加。 |
|r+	| 読み込みと書き込み両方。ファイルが存在しない場合はエラー。 |
|w+	| 読み込みと書き込み両方。ファイルが存在しない場合は作成、存在する場合は内容を消去。 |
|a+	| 読み込みと書き込み両方。ファイルが存在しない場合は作成、存在する場合は末尾に追加。 |

```php
// ファイルを開く
$file = fopen('access.log', 'a') or die('ファイルを開けませんでした！！');
// ファイルの操作
fclose($file);
```

### 2. ファイルをロックする
ファイルに対して同時書き込みが行われるのを防ぐために、ファイルロックを使用します。ロックを行うことで、ファイルへのアクセスを制御し、データの整合性を保ちます。

### ロックモード
| モード |	説明  |
|------|---------|
|LOCK_EX|排他ロック。書き込みや読み込み中に他のプロセスからのアクセスを防ぎます。|
|LOCK_SH|共有ロック。他のプロセスによる読み込みは許可しますが、書き込みは防ぎます。|

```php
// ファイルのロック
flock($file, LOCK_EX);
```

### 3. ファイルに対して書き込みを行う
ファイルを開いた後、`fwrite`関数を使ってデータを書き込みます。データはファイルハンドルを通じて操作され、必要に応じてファイルの内容が更新されます。

```
php
// 書き込み内容を配列$dataにセット
$data[] = date('Y/m/d H:i:s');
$data[] = $_SERVER['SCRIPT_NAME'];
$data[] = $_SERVER['HTTP_USER_AGENT'];
$data[] = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'null';

// ファイルに書き込み
fwrite($file, implode("\t", $data) . "\n");
```

### 4. ファイルを閉じる (ロックの解除)
ファイル操作が完了したら、fclose関数でファイルを閉じます。これにより、ファイルロックが解除され、リソースが解放されます。

```php
// ファイルのロック解除
flock($file, LOCK_UN);
// ファイルのクローズ
fclose($file);
```

## テキストファイルへの書き込みサンプルコード
以下は、アクセスログをテキストファイルに書き込むサンプルコードです。アクセス日時やスクリプト名、ユーザーエージェントなどの情報をaccess.logに追記します。

```php
<?php
// 書き込み内容を配列$dataにセット
$data[] = date('Y/m/d H:i:s');
$data[] = $_SERVER['SCRIPT_NAME'];
$data[] = $_SERVER['HTTP_USER_AGENT'];
$data[] = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'null';

// access.logを追記書き込みモードでオープン
$file = @fopen('access.log', 'a') or die('ファイルを開けませんでした！！');
// ファイルのロック
flock($file, LOCK_EX);
// ファイルの書き込み
fwrite($file, implode("\t", $data) . "\n");
// ロックの解除
flock($file, LOCK_UN);
// ファイルのクローズ
fclose($file);
print 'アクセスログを記録しました。';
?>
```

## ファイルの読み込み
テキストファイルからデータを読み込む際には、fgets関数を使用すると便利です。以下に、ファイルから行単位でデータを読み込み、HTML表形式で表示するサンプルコードを示します。

```php
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>アクセスログ</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" />
</head>

<body>
  <table class="table">
    <thead>
      <tr>
        <th>アクセス日時</th>
        <th>スクリプト名</th>
        <th>ユーザーエージェント</th>
        <th>リンク元のURL</th>
      </tr>
    </thead>
    <tbody>
      <?php
      // ファイルを読み取り専用でオープン
      $file = fopen('access.log', 'r');
      // ファイルを共有ロック
      flock($file, LOCK_SH);
      // 行単位でテキストを読み込み
      while (($line = fgets($file)) !== false) {
        // タブ文字で行単位のテキストを分割
        $data = explode("\t", trim($line));
        print '<tr>';
        // 分割した結果を順に出力
        foreach ($data as $value) {
          print '<td>' . ＄value . '</td>';
        }
        print '</tr>';
      }
      // ロックの解除
      flock($file, LOCK_UN);
      // ファイルのクローズ
      fclose($file);
      ?>
    </tbody>
  </table>
</body>

</html>
```