以前、サーバーの更新の記録を表示させることについて


Webサーバでphpが使用できるなら、filemtime( )でディレクトリの更新日時を取得できます。
<html>
<body>
<ul>
<li><a href="foo">foo</a>
update:
<?php echo date("Y/m/d H:i:s\n", filemtime("foo")); ?>
</li>
<li><a href="bar">bar</a>
update:
<?php echo date("Y/m/d H:i:s\n", filemtime("bar")); ?>
</li>
</ul>
</body>
</html>
ただし、ディレクトリの更新日時は、ファイルを削除しても更新されます。
あと、指定ディレクトリ内にサブディレクトリが存在する場合、そのサブディレクトリ内が更新されても、親のディレクトリの更新日時は更新されません。

というアドバイスをいただいたのですが、サブディレクトリの更新で親のディレクトリの更新日時も更新したいときはどうしたよいでしょうか。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2010/01/30 00:30:02
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答4件)

id:kent013 No.1

回答回数38ベストアンサー獲得回数7

ポイント23pt

http://php.net/manual/ja/function.touch.php

touchで行けると思います.

[ishitoya@sv touchtest]$ mkdir test

[ishitoya@sv touchtest]$ ls -la

合計 12

drwxrwxr-x 3 ishitoya ishitoya 4096 1月 23 01:05 .

drwxrwxr-x 11 ishitoya ishitoya 4096 1月 23 01:05 ..

drwxrwxr-x 2 ishitoya ishitoya 4096 1月 23 01:05 test

[ishitoya@sv touchtest]$ php -r "touch(test);"

[ishitoya@sv touchtest]$ ls -la

合計 12

drwxrwxr-x 3 ishitoya ishitoya 4096 1月 23 01:06 .

drwxrwxr-x 11 ishitoya ishitoya 4096 1月 23 01:05 ..

drwxrwxr-x 2 ishitoya ishitoya 4096 1月 23 01:07 test

親ファイルのみなら

$file = "/home/moge/filename";

touch(dirname($file));

でどうでしょうか?

ファイルが作られたり消されたりすれば,親ディレクトリの日時も変わります.

id:webster

directory Aの下にsubdirectory BとCがあります。BとCのいずれかを更新したさいにindex.phpに更新されたと出したいのです。

2010/01/23 04:07:07
id:kent013 No.2

回答回数38ベストアンサー獲得回数7

ポイント23pt

では,globしてfilemtimeではどうでしょうか.

http://php.net/manual/ja/function.glob.php

ただ,更新された,ということを知るためには以前の更新日時を記憶しておく必要がありますが,そのロジックはあるのでしょうか?

.
|-- A
    |-- B
    `-- C

こういうディレクトリ構成で,

<?php
$subdirectories = array();
foreach(glob("A/*") as $subdirectory){
    $subdirectories[$subdirectory] = filemtime($subdirectory);
}

var_dump($subdirectories);
touch("A/C");

foreach($subdirectories as $subdirectory => $modifiedTime){
    $currentModifiedTime = filemtime($subdirectory);
    if($modifiedTime != $currentModifiedTime){
        echo "時間が更新されています.$subdirectory\n";
    }
}
?>

というスクリプトを動かすと

array(2) {
  ["A/B"]=>
  int(1264187785)
  ["A/C"]=>
  int(1264188220)
}
時間が更新されています.A/C

という出力が得られます.

全く見当違いなら,ポイントいりません.

id:webster

いやそのとおりで、BとCの更新時間をとってきて、そのうちで新しいものを表示させればいいのだと思います。大変恐縮ですが、どういうすくりぷとになりますでしょうか。

2010/01/23 12:18:09
id:kent013 No.3

回答回数38ベストアンサー獲得回数7

ポイント22pt

いちばん簡単なのは,適当なテキストファイルに時間を記録しておくことです.

<?php
$separator = '$%$%$';
$filename = "filemtimes";

$subdirectories = array();
if(file_exists($filename)){
    $file = file($filename);
    foreach($file as $line){
        $line = trim($line);
        $data = explode($separator, $line);
        if(count($data) != 2){
            continue;
        }
        $subdirectories[$data[0]] = $data[1];
    }
}

var_dump($subdirectories);
touch("A/C");
mkdir("A/D");

foreach(glob("A/*") as $subdirectory){
    $currentModifiedTime = filemtime($subdirectory);
    if(isset($subdirectories[$subdirectory]) == false){
        echo "ファイルが追加されました.$subdirectory\n";
    }else if($currentModifiedTime != $subdirectories[$subdirectory]){
        echo "時間が更新されています.$subdirectory\n";
    }
    $subdirectories[$subdirectory] = $currentModifiedTime;
}

$output = array();
foreach($subdirectories as $subdirectory => $modifiedTime){
    $output[] = $subdirectory . $separator . $modifiedTime;
}
file_put_contents($filename, implode("\n", $output));

?>

というスクリプトで

array(2) {
  ["A/B"]=>
  string(10) "1264187785"
  ["A/C"]=>
  string(10) "1264229098"
}
時間が更新されています.A/C
ファイルが追加されました.A/D

という出力が得られます.

でも,本当はチャンとDBに入れるなり何なりして管理したほうがいいとは思います.

ダミーです.

http://a.a.com//

id:tobeoscontinue No.4

回答回数220ベストアンサー獲得回数59

ポイント22pt

親ディレクトリのmtimeとサブディレクトリのmtimeとの比較を繰り返してより新しい(大きい)値を返す関数dirmtime

<?php
function dirmtime($path, $level=3)
{
  $mtime = filemtime($path);
  if (0 < $level--) {
    foreach (glob($path."/*") as $file) {
      if (is_dir($file)) {
       $subtime = dirmtime($file, $level);
       if ($mtime < $subtime) {
         $mtime = $subtime;
//       echo $level.' '.$file."\n";
  } } } }
  return $mtime;
}
?>

まず$mtime = filemtime($path);で親ディレクトリのmtimeを入手します。

親ディレクトリ内のファイルやディレクトリはglobで配列として入手できますので

foreachで回してis_dir()でディレクトリかどうかを調べます。

ディレクトリなら同じく再帰的にdirmtimeでmtimeを入手します。

入手したmtimeが既存のmtimeより新しい(大きい)なら入れ換えます。

全てについて調べれば親ディレクトリ内の中で一番新しいmtimeが分かります。

$levelはディレクトリの階層が深いと時間がかかるので途中で止めるためのもの。

<?php echo date("Y/m/d H:i:s\n", dirmtime("foo")); ?>

更新があった場合に共通のファイル(例えば:SCRIPT_ROOT.'last_update')をtouchするようにできればindex.htmlでは

<?php echo date("Y/m/d H:i:s\n", filemtime(SCRIPT_ROOT.'last_update')); ?>

で更新日時が入手できるのでディレクトリのmtimeを調べる必要が無くなります。こちらの方が断然、負荷は少ないです。

(競合する場合、問題があるかもしれません)

http://q.hatena.ne.jp

id:webster

ありがとうございます!

2010/01/24 04:12:48
  • id:webster
    すみません。dirtimeがfiletimeのうち最も新しいものよりもさらに新しい時間になっているようです。ご教示いただけますでしょうか。
  • id:tobeoscontinue
    // echo $level.' '.$file."\n";
    から//をとって
       echo $level.' '.$file.' '.date(DATE_RFC822, $mtime)."\n";
    としてみて下さい。どの時点のものを見て入れ換えているのかがトレースできます。
    ブラウザーで結果を見る場合は"\n"は"<br>"や"<br />"と変えたほうがいいでしょう。

    階層が深いと表示されるものが多いのでトレースしていくのが大変かもしれません。
    一番最後に表示され時間と同じものを順に遡っていきlevelが0のものが採用されたディレクトリーです。
    levelが0のものが幾つかあるかもしれませんが時間が同じものが採用されたディレクトリーです。

    ターミナルでカレントディレクトリーをdirmtime(".")とするとうまく動作しませんでした。
    多分シェルがカレントディレクトリー内で何かのファイルを更新してそれがカレントディレクトリー
    のmtimeに反映しているのだろうと思っています。
    いずれにしろトレースすればどのディレクトリーのmtimeを採用しているのかがわかるので後は
    そのディレントリーが何故、さらに新しい時間になっているかを調べることになると思います。

    ディレクトリーの階層が
    A/B/C/D/E/F
    となっている場合
    $levelが1ならAとそのサブのBについての新しいものです。
    $levelが2ならAとそのサブのBと更にサブサブのCについての新しいものです。
    $levelが3ならAとそのサブのBと更にサブサブのCと更にサブサブサブのDについての新しいものです。

    そんなに深くする必要がない(1で十分)なら
    function dirmtime($path, $level=3)

    function dirmtime($path, $level=1)
    とするか呼び出す時に
    <?php echo date("Y/m/d H:i:s\n", dirmtime("foo",1)); ?>
    とlevelを指定します。
  • id:webster
    わかりました。Goodsyncを使って定期的に自動的に同期しているのですが、その際にGoodsyncがディレクトリにおいているファイルが更新されるので、それを見て更新しているのだと思います。ただ不思議なことはfilemtime自体もindex.phpで表示させているのですが、それは更新されていないのです。Goodsyncが更新しているファイルは_gsdata_ で始まります。この名前のファイルをチェックしないようにできますでしょうか。よろしくお願い申し上げます。
  • id:tobeoscontinue
    _gsdata_で始まるファイルがある特定のディレクトリー(例えば.goodsyncとする)の中にあるのであればそのディレクトリー
    を対象から外すことは可能です。
    if (is_dir($file)) {

    if (is_dir($file) && (strstr($file, '.goodsync') === FALSE)) { // $fileの文字列の中に.goodsyncがあれば処理しない

    しかし各ディレクトリーの中に_gsdata_で始まるファイルがあるのであれば、これまでのディレクトリーのmtimeを調べると言う
    やりかたでは無理で、ディレクトリー内の各ファイルのmtimeを一つずつ調べることになります(_gsdata_で始まるファイルは除く)。
    function dirmtime($path, $level=3, $mtime=0)
    {
    if (0 < $level--) {
    foreach (glob($path."/*") as $file) {
    if (is_dir($file) && 0 < $level)
    $subtime = dirmtime($file, $level, $mtime);
    elseif (is_file($file) && (strstr($file, '_gsdata_') === FALSE))
    $subtime = filemtime($file);
    if ($mtime < $subtime) {
    $mtime = $subtime;
    // echo $level.' '.$file.' '.date("r", $mtime)."\n";
    } } }
    return $mtime;
    }
    今回の$levelの解釈は異なり、1でそのディレクトリー内のファイルしか調べません。

    このやりかたではファイルが多くなるとどんどん遅くなりますので別の方法を検討したほうがいいと思います。
    Goodsyncが同期時にログファイルなどが入手できるならそれから調べれるといいのですが。

    ファイルの更新があるとディレクトリーのmtimeも更新されると思っていたのですがどうもそうではないようです。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません