Рекурсивный поиск во всех каталогах массива строк в php

Я новичок в PHP-кодировании, и здесь я ищу самый быстрый способ рекурсивного поиска во всех каталогах для массива строк.

я делаю так

$contents_list = array("xyz","abc","hello"); // this list can grow any size
$path = "/tmp/"; //user will give any path which can contain multi level sub directories

$dir = new RecursiveDirectoryIterator($path);

foreach(new RecursiveIteratorIterator($dir) as $filename => $file) {
    $fd = fopen($file,'r');
    if($fd) {
        while(!feof($fd)) {
            $line = fgets($fd);
            foreach($contents_list as $content) {
                if(strpos($line, $content) != false) {
                    echo $line."\n";
                }
            }         
        }
    }
    fclose($fd);
}

Здесь я рекурсивно перебираю все каталоги, а затем снова в каждом файле перебираю массив содержимого для поиска.

Есть ли лучший способ сделать вид поиска? Пожалуйста, предложите более быструю альтернативу.

Спасибо


person inari6    schedule 14.11.2013    source источник
comment
Здесь был аналогичный вопрос: stackoverflow.com /questions/10663641/grep-with-f-like-in-php Может ли это помочь?   -  person ErnestV    schedule 14.11.2013


Ответы (2)


Если вам разрешено выполнять команды оболочки в вашей среде (и при условии, что вы запускаете свой скрипт на * nix), вы можете рекурсивно вызвать собственную команду grep. Это даст вам самые быстрые результаты.

$contents_list = array("xyz","abc","hello");
$path = "/tmp/";
$pattern = implode('\|', $contents_list) ;
$command = "grep -r '$pattern' $path";
$output = array();
exec($command, $output);
foreach ($output as $match) {
    echo $match . '\n';
}

Если действует директива disable_functions и вы не можете вызвать grep, вы можете использовать свой подход с RecursiveDirectoryIterator и читать файлы построчно, используя strpos для каждой строки. Обратите внимание, что strpos требует строгой проверки на равенство (используйте !== false вместо != false), иначе вы пропустите совпадения в начале строки.

Немного более быстрый способ — использовать glob recusively для получения списка файлов и читать эти файлы сразу, а не сканировать их построчно. Согласно моим тестам, этот подход даст вам преимущество во времени примерно на 30-35% по сравнению с вашим.

function recursiveDirList($dir, $prefix = '') {
    $dir = rtrim($dir, '/');
    $result = array();

    foreach (glob("$dir/*", GLOB_MARK) as &$f) {
        if (substr($f, -1) === '/') {
            $result = array_merge($result, recursiveDirList($f, $prefix . basename($f) . '/'));
        } else {
            $result[] = $prefix . basename($f);
        }
    }

    return $result;
}

$files = recursiveDirList($path);
foreach ($files as $filename) {

    $file_content = file($path . '/' . $filename);
    foreach ($file_content as $line) {
        foreach($contents_list as $content) {
            if(strpos($line, $content) !== false) {
                echo $line . '\n';
            }
        }
    }
}

Авторство рекурсивной функции glob принадлежит http://proger.i-forge.net/3_ways_to_recursively_list_all_files_in_a_directory/Opc

Подводя итог, с точки зрения производительности у вас есть следующие рейтинги (результаты в секундах для очень большого каталога, содержащего ~ 1200 файлов рекурсивно, с использованием двух распространенных текстовых шаблонов):

  1. вызов grep через exec() - 2.2015s
  2. использовать рекурсивный glob и читать файлы с file() - 9,4443 с
  3. использовать RecursiveDirectoryIterator и читать файлы с readline() - 15,1183 с
person András Szepesházi    schedule 14.11.2013

Даже в 2013 году существовал — на мой взгляд, гораздо более читаемый — родной для PHP способ рекурсивного обхода дерева каталогов: RecursiveDirectoryIterator.

Взгляните на этот образец:

<?php

  // Initialize Recursive Iterator

  $directory = new RecursiveDirectoryIterator( 'path/to/project/' );
  $iterator = new RecursiveIteratorIterator( $directory );
  $regex = new RegexIterator( $iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH );

  // Iterate over files

  $files = array();
  foreach ( $regex as $info ) {
    // Do something with file to be found at $info->getPathname()
  }

?>

С уважением из Зальцбурга!

person jjarolim    schedule 03.12.2020