Обход папок: рекурсия или итерации

sky_fox

Новичок
Обход папок: рекурсия или итерации

Вопрос следующий - есть массив эталонов вида (ключ - полный путь файла, значение - контрольная сумма файла).
Задача: обходить все папки на сервере и считать размеры и даты изменения файлов и сравнивать с эталоном.

Вопрос: что лучше - рекурсия или делать это итерациями.

Текущий код:
$data_array массив эталонов.

PHP:
function browseDir($dirname)  {
	    global $extensions, $mb_hacked, $report, $data_array;
		$dir = opendir($dirname);
			while (($file = readdir($dir)) !== false) {
				if ($file != "." && $file != "..") {
        			if(is_file($dirname . "/" . $file)) {
        			  $file_parts = pathinfo($dirname . "/" . $file);
        			  if (in_array($file_parts['extension'],$extensions)) {
        			  	$mtime = filemtime($dirname . "/" . $file);
						$size = filesize($dirname . "/" . $file);

        			  	if (array_key_exists($dirname . "/" . $file,$data_array)) {
							$hash = md5($mtime.$size.substr(md5($dirname . "/" . $file),0,-2));
                            if ($data_array[$dirname . "/" . $file] !== $hash) {
								$mb_hacked = true;
								$report .= 'File change warning: `' . $dirname . "/" . $file . '` Date modified: `' . date("d.m.Y H:i",$mtime) . "`\n";
                            }
        			  	} else {
        			  		$mb_hacked = true;
        			  		$report .= 'New file warning: `' . $dirname . "/" . $file . '` Date modified: `' . date("d.m.Y H:i",$mtime) . "`\n";
        			  	}


        			  }
					}

					if(is_dir($dirname."/".$file)) {
						browseDir($dirname."/".$file);
					}
				}
			}
		closedir($dir);
	}

Проблем с ним на данный момент нет, но может ли возникнуть ситуация, что будучи запущенным по крону скрипт не выйдет из рекурсии и завесит сервер. При обходе, скажем 5000+ фолдеров с 1000 файлов в каждом
 

Активист

Активист
Команда форума
Нужно юзать средство ядра Linux - inotify, у меня реализовано на нем...
 

damngood

Мозг был, но ушел...
Ну во-первых у тебя массив будет просто гигантским, 5000*1000 это дофига, есть повод задуматься над другой реализацией, писать эталоны в Файл, БД и обрабатывать все рекурсивно кусками. Потому, что памяти эта вся байда у тебя отожрет не хило.
 

sky_fox

Новичок
Активист,
посмотрю, спасибо.

damngood
массив берется из бд. Но задача не только сравнить с эталоном, а проверить, не появились ли новые файлы.
Я вот думаю, а если хранить в базе не просто таблицу файл - чексам, а связки файлов и фолдеров. И выбирать скажем за прогон 5-10 фолдеров, а затем проверять их начинку. Но ведь заранее не известно. Может статься так, что 4990 фолдеров содержат по 5-10 файлов, а оставшиеся 10 по 2тыс+
 

Активист

Активист
Команда форума
Кстати, в PHP есть поддержка inotify, [m]inotify[/m]

-~{}~ 27.11.09 17:36:

Смотри как реализовано у меня (система контроля за изменениями файлов, весь home хостинг сервера)

http://phpclub.ru/paste/index.php?show=2379
(криво распарсилось)
PHP:
serv001:~# cat ~irj/inotify.log.php
<?php
set_time_limit(0);
ini_set("display_errors", "on");
error_reporting(E_ALL);
ignore_user_abort(true);

// Recrusive found locations
$ret = array();
echo "Looking for www directoies\n";
getLocation($ret, "/home");
echo "Found ".sizeof($dir)." directoried...\nSetting watchs... Take a while...\n";
// Run...
$count = 1;
$wd2path = array();


$fd = inotify_init();
foreach ($ret as $domain => $path) {
        echo "Setting watch for domain {$domain} ( {$path} )...";
        addWatchs($fd, $path);
        echo " sets ({$count}), memory usage ".memory_get_usage()." bytes \n";
}
echo "allready sets {$count} nodes\n";
echo "Watching...\n";



while (true) {
        $events = inotify_read($fd);
        //print_r($events);

        foreach ($events as $event) {
                clearstatcache();

                //echo "* Event: (wd: {$event['wd']}, mask: {$event['mask']} ({$masks[$event['mask']]}), cookie: {$event['cookie']}, filename: {$event['name']}, path {$wd2path[$event['wd']]}\n";
                //echo "* Event: cookie: {$event['cookie']}, filename: {$event['name']}, path {$wd2path[$event['wd']]}\n";


                $mask = $event['mask'];


                if ($mask & IN_ISDIR) {
                        if ($mask & IN_CREATE) {
                                $tmp = inotify_add_watch($fd, $wd2path[$event['wd']]."/".$event['name'],
                                                                IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF);
                                $wd2path[$tmp] = $wd2path[$event['wd']]."/".$event['name'];
                                $count++;
                        }

                        if ($mask & IN_IGNORED) {
                                inotify_rm_watch($fp, $event['wd']);
                                unset($wd2path[$event['wd']]);
                        }
                }

                if (!($mask & IN_ISDIR) && !preg_match("/\.htaccess|\.php|\.phtml|\.sh$/i", $event['name'])) {
                        // skip event
                        continue;
                }

                if (!($mask & IN_ISDIR) && (
                                                                        preg_match("/^sql_/", $event['name']) ||
                                                                        $event['name'] == "drop.php"
                                                                        )) {
                        continue;
                }

                $fId = fopen("/root/inotify/".date("Y-m-d").".log", "a+");

                fputs($fId,
                                        "[".date("H:i:s")."] {$wd2path[$event['wd']]}/{$event['name']} ".($mask & IN_ISDIR ? "D\n" : "F\n"));

                if ($mask & IN_ACCESS) fputs($fId, "- File was accessed (read)\n");
                if ($mask & IN_MODIFY) fputs($fId, "- File was modified\n");
                if ($mask & IN_ATTRIB) fputs($fId, "- Metadata changed (e.g. permissions, mtime, etc.)\n");
                if ($mask & IN_CLOSE_WRITE) fputs($fId, "- File opened for writing was closed\n");
                if ($mask & IN_CLOSE_NOWRITE) fputs($fId, "- File not opened for writing was closed\n");
                if ($mask & IN_OPEN) fputs($fId, "- File not opened for writing was closed\n");
                if ($mask & IN_MOVED_TO) fputs($fId, "- File or directory was moved to\n");
                if ($mask & IN_MOVED_FROM) fputs($fId, "- File moved out of watched directory\n");
                if ($mask & IN_CREATE) fputs($fId, "- File or directory created in watched directory\n");
                if ($mask & IN_DELETE) fputs($fId, "- Watched file or directory was deleted\n");
                if ($mask & IN_MOVE_SELF) fputs($fId, "- Watch file or directory was moved self\n");
                if ($mask & IN_CLOSE) fputs($fId, "- Equals to IN_CLOSE_WRITE | IN_CLOSE_NOWRITE\n");
                if ($mask & IN_MOVE) fputs($fId, "- Equals to IN_MOVED_FROM | IN_MOVED_TO\n");
//              if ($mask & IN_ALL_EVENTS) echo "- Bitmask of all the above constants";
                if ($mask & IN_UNMOUNT) fputs($fId, "- File system containing watched object was unmounted\n");
                if ($mask & IN_Q_OVERFLOW) fputs($fId, "- Event queue overflowed (wd is -1 for this event)\n");
                if ($mask & IN_IGNORED) fputs($fId, "- Watch was removed (explicitly by inotify_rm_watch()  or because file was removed or filesystem unmounted\n");
                if ($mask & IN_ISDIR) fputs($fId, "- Subject of this event is a directory\n");
                if ($mask & IN_ONLYDIR) fputs($fId, "- Only watch pathname if it is a directory (Since Linux 2.6.15)\n");
                if ($mask & IN_DONT_FOLLOW) fputs($fId, "- Do not dereference pathname if it is a symlink (Since Linux 2.6.15)\n");
                if ($mask & IN_MASK_ADD) fputs($fId, "- Add events to watch mask for this pathname if it already exists (instead of replacing mask).\n");
                if ($mask & IN_ONESHOT) fputs($fId, "- Monitor pathname for one event, then remove from watch list\n");
                fclose($fId);

        }

}



function getLocation(&$ret, $dir, $depth = 1) {
        $d=opendir($dir);
        while (($f = readdir($d)) !== false) {
                $path = $dir."/".$f;
                //echo $path."\n";
                if ($f != ".." && $f != "." && is_dir($path) && array_search($f, $ret) === false && $f != "email") {
                         if (!preg_match("/^[a-z0-9-\.]+\.[a-z]{2,5}$/i", $f)) {
                                if ($depth <= 3) {
                                        getLocation($ret, $path, $depth+1);
                                }
                         } else {
                                //echo $path." {$f}\n";
                                if ($depth > 1) $ret[$f] = $path;
                         }
                }
        }
}

function addWatchs(&$obj, $path, $skip = array("daemon")) {
        global $count,$wd2path;

        $tmp = inotify_add_watch($obj, $path,
                                                                IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF);
        //echo "   {$path} (ok)\n";
        $wd2path[$tmp] = $path;
        $count++;

        if (is_dir($path)) {

                $d = opendir($path);

                while (($f = readdir($d)) !== false) {
                        $lpath = $path."/".$f;
                        if ($f != ".." && $f != "." && is_dir($lpath) && array_search($f, $skip) === false) {
                                addWatchs($obj, $lpath, $skip);
                                continue;
                        }

/*                      if (!is_dir($lpath)) {
                                if (preg_match("/.htaccess|.php|.inc|.phtml$/i", $f)) {
                                        $tmp=inotify_add_watch($obj, $lpath,
                                                                IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF);
//                                      echo "   {$lpath} (ok)\n";
                                        $wd2path[$tmp] = $lpath;
                                        $count++;
                                }
                        }*/
                }
        }

}
?>serv001:~#
 
Сверху