PHPでテキストログ出力部分を制作しようとしたときに、ふと思いました。
「年、月別でフォルダ管理すれば使いやすいのではないだろうか?」
テキストログは通常一つのフォルダに出力します。
ただそれだと、いつのログであるかがわかりにくいと思いました。
そこでログフォルダに「年」フォルダと「月」フォルダをPHPで自動で作って管理すれば、ログを調査しやすいと考えました。
事実、過去のログも格段に探しやすくなりました。
その際に、PHPでフォルダ作成する際に手間取ったことがありましたので、忘備録として記録いたします。
PHPでフォルダを作成するにはmkdir()関数を使用する
PHPでフォルダ作成するには、mkdir()関数を使用します。
mkdir([フォルダ名], [パーミッション])
というわけで、日付からフォルダを作るサンプルをまず作ってみました。
<?php
$year = date("Y");
$month = date("m");
$day = date("d");
mkdir("test/${year}/${month}/${day}", 0705);
?>
当日の年、月、日の階層をまとめてフォルダ化します。
ところがこの記述ではとエラーとなりフォルダは作成されませんでした。
「そのディレクトリは存在しません」
というようなエラーになりました。
まだフォルダ作成していないのに、なぜフォルダが無いエラーになるの?
と考えましたが、次のようなことでした。
mkdir()は複数階層フォルダを一度に作ろうとするとエラーになる。
例えば次のような記述の場合を考えます。
mkdir(“test/2022/05/28”);
この記述では以下の4つのフォルダを指定しています。
- [test]
- [2022]
- [05]
- [28]
mkdir()関数ではこの場合、一番最後である[28]のフォルダを作成しようとします。
しかし、[2022][05]フォルダが存在していないため、ディレクトリが存在していないエラーになるのです。
この場合、ひとつひとつフォルダを作っていくしかないのかなぁ。
と思いましたが、何とかする方法がありました。
recursiveオプションを指定すれば複数階層フォルダをまとめて作成できます
mkdir()関数のマニュアルを見てみると、recursiveオプションに次のようなことが書かれていました。
https://www.php.net/manual/ja/function.mkdir.php
recursive
directory
で、入れ子構造のディレクトリの作成を許可します。
入れ子構造?
って何?
と思いましたが、要は階層フォルダのことです。
もしかしてこのオプションをつければ複数階層フォルダをまとめて作成できるのではないかと考え、サンプルプログラムを次のように書き換えました。
<?php
$year = date("Y");
$month = date("m");
$day = date("d");
mkdir("test/${year}/${month}/${day}", 0705, true);
?>
最初サンプルとの違いは、mkdir()関数の3番目の引数に「ture」を入れたことです。
この3番目の引数がrecursiveオプションです。
ちなみに省略すると「false」扱いになります。
実際に試してみたところ、次のようになりました。
見事に複数階層フォルダが一度に作成できました。
めでたしめでたし。
と思いましたが、実用性を考えるとこれだけではだめでした。
問題点:一度作成したフォルダをもう一度作成しようとするとエラーになる。
ログ目的なので、ログが発生する度にフォルダ作成しようとします。
つまり同じフォルダ名を2回以上作成しようとします。
先ほどのサンプルを、フォルダが作成された後にもう一度実行させるとこうなりました。
「すでにそのフォルダは存在しています。」エラーになりました。
そりゃそうですよね。
ワーニングではありますが、毎回エラーを吐くのはあまりよろしくありません。
この場合はどうすれば…。
と考え頭をひねりました。
そしてひらめきました。
フォルダが存在するかどうかチェックすればOK
phpにはフォルダが実在しているかどうかをチェックする関数があります。
file_exists()関数です。
- 存在していたらture
- 存在していなかったらfalse
が返ります。
ログ発生毎にフォルダ存在チェックをし、フォルダがなかったらmkdir()関数を呼べばエラーを吐かなくなります。
そこで、サンプルを次のように書き換えしました。
<?php
$year = date("Y");
$month = date("m");
$day = date("d");
if (file_exists("test/${year}/${month}/${day}") == false)
{
mkdir("test/${year}/${month}/${day}", 0705, true);
}
?>
if文でfile_exists()関数を呼び、false(フォルダが存在していない)ならばmkdir()(フォルダ作成)します。
このようにすることでフォルダが存在しない時だけフォルダ作成することができるようになりました。
ちなみにフォルダを削除する場合のやり方
一定数ログがたまったら、自動削除することも想定する必要があります。
その場合は、rmdir()関数を使用します。
ただ、rmdir()関数はmkdir()関数と異なり、階層フォルダをまとめて消すオプションはありませんでした。ひとつひとつ削除するしかありません。
また、フォルダ内にファイルが存在している場合はファイルを削除してからフォルダを消す必要があります。
ファイルとフォルダを削除するのは、ファイルとフォルダを作るよりも手間がかかります。
本記事がまたお役に立てば幸いです。