preg_match_all между динамическими тегами

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

$vHostConfig = '    <VirtualHost *:80>
        ServerName localhost
        DocumentRoot c:/wamp/www
        <Directory  "c:/wamp/www/">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
    <VirtualHost *:8080>
        ServerName testing.com
        DocumentRoot c:/wamp/www/testing.com
        <Directory  "c:/wamp/www/testing.com">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
    <VirtualHost 127.0.0.1:80>
        ServerName testing2.com
        DocumentRoot c:/wamp/www/testing2.com
        <Directory  "c:/wamp/www/testing2.com">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
#    <VirtualHost *:80>
#        ServerName testing3.com
#        DocumentRoot c:/wamp/www/testing3.com
#        <Directory  "c:/wamp/www/testing3.com">
#            Options +Indexes +Includes +FollowSymLinks +MultiViews
#            AllowOverride All
#            Require local
#        </Directory>
#    </VirtualHost>';

preg_match_all(<<what to put here>>, $vHostConfig, $vHostConfigMatches);

Я хотел бы получить только активные конфигурации без символа # в начале строки, что означает, что у меня должно быть три строки, начинающиеся с <VirtualHost и заканчивающиеся </VirtualHost> в массиве $ vHostConfigMatches. Это возможно?


person Dan    schedule 02.11.2016    source источник
comment
хотя регулярное выражение действительно может это делать, стоит отметить, что какой-то парсер DOM будет намного лучше и, вероятно, более эффективным при этом. примечание 1 :: примечание 2   -  person Martin    schedule 02.11.2016
comment
Я не использую этот код в браузере, это какой-то специальный код для управления моими виртуальными хостами, поэтому я могу встроить пользовательские функции в свое меню wamp.   -  person Dan    schedule 02.11.2016
comment
XHTML по-прежнему имеет структуру DOM, независимо от того, с чем вы его просматриваете.   -  person Martin    schedule 02.11.2016


Ответы (3)


Вы можете использовать это регулярное выражение:

preg_match_all('/^\h*<VirtualHost.*?>.*?\R\h*<\/VirtualHost>/sm',
               $vHostConfig, $vHostConfigMatches);  

Обратите внимание, что массив $vHostConfigMatches будет иметь дополнительный уровень вложенности, поэтому просто возьмите первый с reset:

print_r(reset($vHostConfigMatches));
person trincot    schedule 02.11.2016
comment
Элегантный ответ, отлично работает. Очень признателен :-) - person Dan; 02.11.2016

Вы можете разделить его по строкам: $lines = explode(PHP_EOL, $vhostConfig);

Отфильтровать все прокомментированные строки: $lines = array_filter($lines, function ($ele) { return substring($ele, 0) != "#"; });

Снова соберите: $vhostConfig = implode(PHP_EOL, $lines);

Затем используйте регулярное выражение для извлечения каждого виртуального хоста (вам может понадобиться что-то более точное: preg_match_all("@<VirtualHost [\d\.\*:]+>(.*?)</VirtualHost>@", $vhostConfig, $vhostConfigMatches);

Не проверено, но должно дать вам представление. Это также имеет то преимущество, что игнорирует любую прокомментированную строку в действительном виртуальном хосте.

person Kayson    schedule 02.11.2016
comment
Нравится ваш подход, мне пришлось немного отредактировать ваш код $lines = array_filter($lines, function ($ele) { return substr($ele, 0, 1) != "#"; });, к сожалению, preg_match_all не работает никаких предложений? - person Dan; 02.11.2016
comment
Это был правильный ответ только для захвата активных конфигураций, но шаблон регулярного выражения в ответе trincot верен для разделения активных конфигураций на три элемента массива - person Dan; 02.11.2016

Хотя ответ @ trincot работает нормально, он использует квантификатор .*? (ленивый), который делает механизм регулярных выражений очень активным: this regex101 показывает, что в этом примере требуется 950 шагов.

Поэтому я думаю, что, даже если он кажется немного более сложным, этот простой фрагмент PHP будет работать быстрее:

$result = array_reduce(
  explode(PHP_EOL, $str),
  function($result, $line) {
    if (trim($line[0]) <> '#') {
      if (strpos($line, '<VirtualHost') !== false) {
        $result[] = $line;
      } else {
        $result[count($result) - 1] .= $line;
      }
    }
    return $result;
  },
  []
);

Сразу это просто:

  • превращает исходную строку в массив строк
  • оставь любой комментарий
  • заполняет необходимый результат, как ожидалось
person cFreed    schedule 02.11.2016