PHPでJSONファイルの扱い方を徹底解説!作成、追記、読込などの基本的な動作と注意するべきポイントとは?
この記事からわかること
- phpでのJSONファイルの扱い方
- json_encode/decode関数の使い方
- 取得したデータの参照の仕方
- PHPの連想配列とオブジェクトの違い
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
phpでチャット機能を作ろうとした時にデータの格納先をデータベースにするかテキストファイルにするか悩みました。その時に名前だけは知っていたJSONファイルという存在を知りphpでの扱い方を学習したのでまとめていきたいと思います。
JSONファイルをphpで扱おう
そもそも「JSONファイル」とはどのようなものか整理しておきたいと思います。
◆JSONファイルの特徴
- javascriptのオブジェクトの記法に似たテキストファイル
- 文字列や数値だけでなく真偽値や連想配列(オブジェクト)も扱える
- シングルクォーテーションは使えない
- コメントアウトも使えない
- 記法が正しく書かないと思わぬ動作を生んでしまうかも?
- さまざまなプログラミング言語にも対応
色々と細かい制限はありますが、テキストファイルなのに連想配列が使えるということはとても大きなメリットです。データの追加や削除、取得の簡単さが全く違うのでデータ管理には重宝されています。
そしてphpでも「JSONファイル」を操作することができます。
今回はphpで動的にJSONファイルを作成し、そこにデータを記述していく処理を作ってみながら解説していきたいと思います。
phpでJSONファイルを扱える関数
JSONファイルと関係する関数で以下の4つを紹介いたします。
- file_put_contents関数:ファイルにデータを書き込む(作成する)
- file_get_contents関数:ファイルのデータを読み込む
- json_encode関数:データをJSON用にエンコード(符号化)する
- json_decode関数:データをJSON用にデコード(復号)する
基本的にこの4つの関数があればある程度の操作を行うことができます。
file_put_contents関数
この関数を知る前に、JSONファイルの作成方法も見ておきましょう。JSONファイルを作成するには2つの方法があります。
- 自分で作るか
- 必要な時にphpに動的に作成してもらうか
1つ目の方法はhtmlファイルやphpファイルを作るときと同じくエディタなどで新規作成で拡張子を「.json」としたファイルを作ることです。この中に正しい記法でコードを書き込めば立派なJSONファイルの出来上がりです。
2つ目はphpの組み込み関数の1つ「ファイルシステム関数」を利用した方法です。これが「file_put_contents関数」になります。
file_put_contents関数はファイルを操作するfopen関数やflock関数、fwrite関数などを集約して一回で呼び出すことができる関数です。
●file_put_contents関数
file_put_contents(string $filename, mixed $data, int $flags)
file_put_contents( ファイルパス , データ , フラグ )
file_put_contents(test.php,$data,FILE_APPEND | LOCK_EX)// 例
●特徴
- 指定したファイルパスのファイルにデータを書き込む(上書きする)
- 指定したファイルパスがなければファイルを自動で作成して書き込む
- フラグを指定することで上書きではなく「追記」や「排他ロック」を設定できる※
※フラグ | 説明 |
---|---|
FILE_APPEND | 指定したファイルがあれば追記で書き込む |
LOCK_EX | ファイルに排他ロックをかける |
file_put_contents関数を使えばファイルがなければ動的に作成し、あればそこに追記させることが可能です。この挙動を頭に入れておきながらJSONファイルを扱っていきたいと思います。
file_get_contents関数
「file_get_contents関数」も先ほどと同様にfopen関数やflock関数、そしてfgetcsv関数/fgets関数などを集約して一回で呼び出すことができる関数です。
●file_get_contents関数
file_get_contents(string $filename,bool $use_include_path = false,resource $context = ?,int $offset,int $length)
file_get_contents( ファイル名 ,インクルードパス,コンテキスト,読込開始位置,読み込むバイト数)
file_get_contents($file)//例1:ファイルから全てのデータを抜き出す
file_get_contents($file,false,null,5,10)//例2:5文字目から10文字抜き出す
●特徴
- 指定したファイルのパスからデータを抜き出す
- offsetとlengthを指定することで抜き出し位置と抜き出し量を設定
- インクルードパスとコンテキストは使わない時はfalseとnullを指定
json_encode関数
「json_encode関数」は渡したデータをJSON形式に変換してくれる関数です。HTMLで特殊な文字となる「"」や「/」は自動でエスケープ処理を施してくれます。
// ame 25 東京都 でエンコードすると...
{"name":"ame","age":"25","from":"\u6771\u4eac\u90fd"}
// "kasa" 19 /広島 県/ でエンコードすると...
{"name":"\"kasa\"","age":"19","from":"\/\u5e83\u5cf6\u3000\u770c\/"}
このように「空白」は「\u3000」といったエスケープシーケンス記法に変換し、「"」などは「\」をつけてエスケープ処理を施してくれます。
さらにフラグを指定すれば「"」などをエスケープシーケンス記法に変換することもできます。
json_encode(mixed $value, int $flags = 0, int $depth = 512)
json_encode(データ, フラグ※ , ネストの深さ)
※フラグ名 | 説明 |
---|---|
JSON_HEX_TAG | 「<」と「>」をそれぞれ「\u003C」と「\u003E」に変換 |
JSON_HEX_QUOT | 「"」を「\u0022 」に変換 |
json_decode関数
先ほどエンコードした文字列は人間では識別できない文字列へと変換されてしまいました。このままデータを取り出そうとしても使えないデータになってしまうので一度元に戻さないといけません。
それが「json_decode関数」の役割です。
json_decode(string $json,?bool $associative = null,int $depth = 512,int $flags = 0)
json_decode(json文字列,true/false/null※,ネストの深さ,フラグ)
※associativeの値 | 説明 |
---|---|
true | 返される値は連想配列型 |
false | 返される値はobject型 |
null | フラグの設定値次第 |
入力値をJSONファイルに格納するプログラムを作る
先ほどのコードたちの挙動を確かめるために実際にユーザからの入力値をJSONファイルに格納するプログラムを作ってみましょう。
今回は簡単に名前、年齢、出身地を入力してもらいその情報をJSONファイルに格納していくプログラムを作っていきます。
まずはフォーム部分のHTMLを記述していきましょう。
<form action="test.php" method="post">
<p>お名前</p>
<input type="text" name="name" value="" required>
<p>年齢</p>
<input type="number" name="age" value="" required>
<p>出身地</p>
<input type="text" name="from" value="" required>
<input type="submit" name="submit" value="送信">
</form>
これで$_POSTでそれぞれの入力値を取得することができるようになりました。
続いては「JSON」ファイルに記述する準備をしていきます。
連想配列にデータを格納
まずは変数$J_fileに作成したいファイル名を記入します。ファイル名のみを記入することで相対パスになり、同じディレクトリ内に指定したファイル名がなければ自動で生成するようにします。自動生成の前に入力値を連想配列の中に格納します。
<?php
// ファイルへのパスを格納 同ディレクトリなのでファイル名のみ
$J_file = "person.json";
$data = []; // 空の配列を格納
// 連想配列の中に$_POSTのデータを格納
$data["name"] = $_POST['name'];
$data["age"] = $_POST['age'];
$data["from"] = $_POST['from'];
// 続けてここに処理を書いていく
?>
JSONファイルの中の構造
JSONファイルの中はこのような構造で作っていきたいと思います。
{"person":[{1人目},{2人目},...]}
{"キー値":[配列の要素1,配列の要素2,...]} // 配列の要素の中に人情報の連想配列
連想配列(person)の中の配列([])の中に人の連想配列({1人目})
JSONファイルで扱うのは確かに操作性は高いですが、ネスト(階層)が深くなりがちなのでややこしくなるのが難点ですね。。。
JSONファイルの有無で分岐処理
次にJSONファイルが同ディレクトリ内にあるかどうかで処理を分岐していきます。
ファイルがある場合の処理 | ファイルがない場合の処理 |
---|---|
ファイルデータをデコードせずに読み込む #1 | 入力データをJSON形式にエンコード $1 |
大枠の連想配列と配列の中に 入力データを入れるため 末尾の「 ]} 」を切り取る #2 |
大枠の連想配列の中に入れるため 「 '{"person":['.入力データ.']}' 」と記述 $2 |
入力データをJSON形式にエンコード #3 | 入力データをファイルに書き込む $3 |
ファイルデータ+入力データ+「 ]} 」と記述 #4 | 終了 |
構築したデータをファイルに書き込む #5 | 終了 |
if($file = file_get_contents($J_file)){ // #1
// ファイルがある場合の処理
$file = mb_substr($file,0,mb_strlen($file)-2);// #2
$json = json_encode($data);// #3
$json = $file.','.$json.']}';// #4
file_put_contents($J_file,$json,LOCK_EX);// #5
// 次の処理はここに書いていく
}else{
// ファイルがない場合の処理
$json = json_encode($data);// $1
$json = '{"person":['.$json.']}';// $2
file_put_contents($J_file,$json,LOCK_EX);// $3
}
JSONファイルの連想配列の中にデータを追記していくには少しコツが必要です。
「file_put_contents関数」の追記モード(FILE_APPEND)で追記していくと1番最後の配列と連想配列の「]}」の後ろに追記することになるのでJSON形式が崩れて構造がおかしくなってしまいます。
JSON構造を保って追記するためにここでは力技で追記ロジックを自作しています(#4部分です)。あくまで配列の中の要素を追加していくので「]}」を一度削除しその後にまた「]}」を追加して構造を保っています。
何か他に別の良い方法があれば教えてください。。。笑
JSONファイルからデータを抜き出す
あとはデータの取り出し方を理解すればJSONファイルを自由に扱えるようになります。
では実際に取り出したデータを表示するところまでやってみます。
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
file_put_contents($J_file,$json,LOCK_EX);// #5
// ここから新しいコード
$file = file_get_contents($J_file); //新しいファイルを読み込む
$file = json_decode($file); // デコード
// 連想配列(オブジェクト)が$fileに格納される
}else{
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
ここから構造がややこしかった分データを取り出すのもややこしくなります。まずはデコードして格納した $fileには連想配列(オブジェクト)が格納されます。
つまり現段階のファイルの中身は以下の状態です。
$file ⇨ {"person":[配列]}
✖︎$file['name'] //いきなり名前は呼び出せない
✖︎$file[0] //配列の0番目(1人目)の要素も取得できない
✖︎$file['person'] //phpの連想配列としても取得できない
○$file->person //phpのオブジェクト変数として認識される
ここがややこしい点です。JSONファイルの時は連想配列とオブジェクトの違いはなく(?)同じものとして認識してきましたが、ことPHPでは連想配列とオブジェクトは異なる扱い方になります。
PHPの連想配列とオブジェクトの違い
途中までは同等に扱ってきた連想配列とオブジェクトですがphpでは取得の仕方が異なります。
JSONの連想配列を取得するとPHPではオブジェクト型として取得します。型と中身を確認できるvar_dumpで確認してみましょう。
$file = json_decode($file);
var_dump($file);
//var_dump($file)の結果
object(stdClass)#4 (1) { ["person"]=> array(3) { [0]=> object(stdClass)#1 (3) { ["name"]=> string(18) "デザイン太郎" ["age"]=> string(2) "21" ["from"]=> string(9) "愛知県" }...
オブジェクト型はいわゆるクラスなどで利用する型になります。なので「person」は$fileオブジェクトのメソッド名ということになるのでしょうか。
もちろん取得の仕方も変わってきます。先ほども書きましたが連想配列の取得の仕方では取得できずメソッドの取得のコードで取得ができるようになります。そしてさらに「person」の中には配列が格納されているのでわかりやすく変数$arrayに配列を格納します。
✖︎$array = $file['person'] //phpの連想配列としても取得できない
○$array = $file->person //phpのオブジェクト変数として認識される
そしてようやく配列の中の要素を取得することができます。今回は2人目の情報取得してみましょう。
$object = $array[1]
配列の2人目(要素番号は1)で取得できるのはまたしてもオブジェクトです。今度は人の情報(入力値)が格納されたオブジェクトになります。
そしてようやく2人目の情報に格納されている名前を表示することができました。
echo $object->name
一連のコードにするとこのような感じです。
$file = file_get_contents($J_file); // ファイルの中身を全て取得
$file = json_decode($file); // デコードして、大枠のオブジェクトを取得
$array = $file->person; // オブジェクトから配列を取得
$object = $array[0]; // 配列からオブジェクトを取得
echo $object->name; // オブジェクトから入力値を取得し表示
これでようやく入力値を取得することができました。JSONファイルはデータ操作が非常に楽ですがデータの挿入と取得にはネストが深くなればなるほどややこしくなってしまうデメリットも存在します。まだ私の知識が浅いので冗長なコードになっているのかもしれませんが使いこなすにはもう少し時間がかかりそうです。。
PHPでJSONファイルを扱う時の注意点
- データを追記するときは組み込む場所に注意
- ネストを深くしすぎると構造が複雑になる
- 取得する時はデータ型に要注意!!
- 連想配列とオブジェクトのデータの取得方法の違いに気を付ける
それでもデータ操作のしやすさと軽量さ、使い勝手の良さがあるのでメリットの方が大きいですね。
まだまだ勉強中ですので間違っている点や至らぬ点があれば教えていただけると嬉しいです。
ご覧いただきありがとうございました!