PHPでJSONファイルを安全に管理する方法を徹底解説|flock()による排他制御とデータ保存の仕組みを初心者向けに解説

2026年7月13日月曜日

Laravel PHP バックエンド プログラミング

t f B! P L

PHPでJSONファイルを安全に管理する方法|flock()による排他制御と出力管理をわかりやすく解説

PHPで小規模なWebシステムを作るとき、「データベースを使わずに簡単にデータを保存したい」と思ったことはありませんか?

そんなときによく利用されるのがJSONファイルをデータベース代わりに利用する方法です。

今回紹介するコードでは、ユーザー情報やメッセージをJSONファイルへ保存しています。ただ保存するだけではなく、複数ユーザーが同時にアクセスしてもデータが壊れないようにflock()による排他制御も実装されています。

結論からいうと、このシステムは「JSONファイルを簡易データベースとして利用し、全件読み込み→メモリ上で更新→全件上書き保存する仕組み」です。


PHPの出力(永続化データ)はJSONファイルで管理されている

このシステムではデータベースを使わず、次の2つのJSONファイルが実質的なデータベースになっています。

project
├─ data
│  ├─ users.json
│  └─ messages.json
└─ lib
   └─ common.php

保存先は定数で管理されています。

// データ保存先ディレクトリ
define('DATA_DIR', __DIR__ . '/../data');

// ユーザー情報
define('USERS_FILE', DATA_DIR . '/users.json');

// メッセージ情報
define('MESSAGES_FILE', DATA_DIR . '/messages.json');

例えば次のコードを実行すると、users.jsonへ保存されます。

// ユーザー一覧を保存
saveUsers($users);

PHPでJSONファイルを読み込む仕組み

すべての読み込み処理はreadJsonFile()を経由します。

function readJsonFile(string $path): array

読み込みの流れ

JSONファイル
      ↓
fopen()
      ↓
LOCK_SH取得
      ↓
内容を読み込む
      ↓
json_decode()
      ↓
PHP配列として返す

途中で使われている重要な処理がこちらです。

// 読み取り専用の共有ロック
flock($fp, LOCK_SH);

LOCK_SHは「共有ロック」と呼ばれます。

処理 実行可否
読込A
読込B
書込 ×(待機)

つまり複数人が同時に閲覧しても問題ありません。しかし、書き込み中のデータを途中で読んでしまうことは防止されています。


PHPでJSONファイルへ書き込む仕組み

保存処理はすべてwriteJsonFile()が担当します。

function writeJsonFile(string $path, array $data): bool

保存の流れ

PHP配列
   ↓
json_encode()
   ↓
LOCK_EX取得
   ↓
既存データ削除
   ↓
新しいJSONを書込
   ↓
保存完了

もっとも重要なのが排他ロックです。

// 書き込み中は他の処理を待機させる
flock($fp, LOCK_EX);
処理 実行可否
読込 ×
書込 ×
別の書込 ×

例えば2人が同時に投稿した場合でも次のように順番待ちになります。

ユーザーA投稿
      ↓
LOCK_EX取得
      ↓
保存
      ↓
LOCK解除
      ↓
ユーザーB保存開始

この仕組みによってファイル破損を防いでいます。


全件上書き保存方式とは?

このシステムは「追記保存」ではありません。

毎回すべて読み込み、更新してから保存しています。

全件読込
    ↓
配列更新
    ↓
JSON再生成
    ↓
全件上書き保存

保存時には次の2つが実行されます。

// 既存データを空にする
ftruncate($fp, 0);

// 書き込み位置を先頭へ戻す
rewind($fp);

その後、新しいJSONを書き込みます。

// 更新後のJSONを書き込む
fwrite($fp, $json);

そのため、常に最新状態のJSONファイルが完成します。


ユーザー情報はどのように保存されるのか

新規登録時はcreateUser()が実行されます。

$newUser = [
    'id' => uniqid('user_', true),
    'username' => $username,
    'password_hash' => password_hash($password, PASSWORD_DEFAULT),
    'created_at' => date('Y-m-d H:i:s'),
];

保存後のusers.jsonは次のようになります。

[
  {
    "id":"user_xxx",
    "username":"suzuki",
    "password_hash":"$2y$10$...",
    "created_at":"2026-07-13 15:00:00"
  }
]

メッセージはどのように保存されるのか

投稿時はaddMessage()が呼ばれます。

$newMessage = [
    'id' => uniqid('msg_', true),
    'user_id' => $userId,
    'username' => $username,
    'message' => $message,
    'created_at' => date('Y-m-d H:i:s'),
];

messages.jsonには次のように保存されます。

[
  {
    "id":"msg_1",
    "user_id":"user_1",
    "username":"suzuki",
    "message":"こんにちは",
    "created_at":"2026-07-13 15:10:00"
  }
]

500件制限がある理由

このコードには実務でもよく使われる工夫があります。

// 最新500件だけ保持する
if (count($messages) > 500) {
    $messages = array_slice($messages, -500);
}

古いデータを削除することで次のメリットがあります。

  • JSONファイルの肥大化を防ぐ
  • メモリ使用量を抑える
  • 読み込み速度を維持する
  • 保存時間を短縮できる

実際の保存タイミング

ユーザー登録

createUser()
    ↓
saveUsers()
    ↓
writeJsonFile()
    ↓
users.json更新

メッセージ投稿

addMessage()
    ↓
saveMessages()
    ↓
writeJsonFile()
    ↓
messages.json更新

よくある失敗例

  • flock()を使わず同時書き込みでファイルが壊れる
  • json_decode()の失敗チェックをしていない
  • password_hash()を使わず平文パスワードを保存する
  • 大量データでもJSON保存を続けてしまう
  • 例外処理を実装せず保存失敗に気付けない

実務でのベストプラクティス

  • 必ずLOCK_SH・LOCK_EXで排他制御を行う
  • JSON保存は数百件程度までにする
  • パスワードはpassword_hash()で暗号化する
  • 保存失敗時のログ出力を追加する
  • アクセス数が増えたらSQLiteやMySQLへ移行する

この方式のメリット・デメリット

メリット デメリット
DB不要 大量データに弱い
実装が簡単 毎回全件保存する
バックアップが容易 同時アクセスが増えると遅くなる
学習しやすい 検索性能が低い

まとめ

このコードの最大の特徴は、JSONファイルを簡易データベースとして利用しながら、flock()による排他制御で安全性を確保している点です。

データ保存の流れは非常にシンプルです。

全件読み込み → 配列更新 → JSONへ変換 → 全件上書き保存

小規模な掲示板やチャットアプリ、学習用システムでは非常に扱いやすい構成ですが、アクセス数やデータ量が増えると処理負荷が高くなるため、本番環境ではSQLiteやMySQL、PostgreSQLなどのデータベースへの移行を検討するのが一般的です。


初心者向け学習ポイント

  • JSONファイルとデータベースの違いを理解する
  • json_encode()・json_decode()の使い方を覚える
  • flock()による排他制御の重要性を学ぶ
  • password_hash()とpassword_verify()を使った認証を理解する
  • ファイル操作(fopen・fwrite・fclose)の基本を身につける

実務での活用例

  • 社内ツールの試作品
  • 小規模チャットシステム
  • お問い合わせフォーム
  • 設定ファイル管理
  • 簡易CMSやメモアプリ

次に学ぶべき関連記事候補

  1. PHPのflock()を使った排他制御を徹底解説
  2. PHPでJSONファイルをデータベース代わりに使う方法
  3. PHPのpassword_hash()とpassword_verify()による安全な認証
  4. PHPでSQLiteを使ったデータ管理入門
  5. MySQLとPostgreSQLの違いと選び方

このブログを検索

Welcome



旅するWebライター「Hide」のブログへようこそ!

2年間の世界一周を終え、今は旅の思い出を言葉にしながら、AIやプログラミングという新しい冒険を楽しんでいます。最新技術を味方につけて、もっと自由でクリエイティブな発信を続けていきます!

人気の投稿

QooQ